mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-24 14:33:02 +02:00
Check amounts of stars/TON.
This commit is contained in:
parent
6f305c8974
commit
4840a9094b
24 changed files with 474 additions and 150 deletions
|
@ -2911,6 +2911,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_credits_small_balance_star_gift" = "Buy **Stars** to send gifts to {user} and other contacts.";
|
||||
"lng_credits_small_balance_for_message" = "Buy **Stars** to send messages to {user}.";
|
||||
"lng_credits_small_balance_for_messages" = "Buy **Stars** to send messages.";
|
||||
"lng_credits_small_balance_for_suggest" = "Buy **Stars** to suggest post to {channel}.";
|
||||
"lng_credits_small_balance_fallback" = "Buy **Stars** to unlock content and services on Telegram.";
|
||||
"lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars.";
|
||||
"lng_credits_enough" = "You have enough stars at the moment. {link}";
|
||||
|
@ -4478,6 +4479,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_suggest_warn_text_stars" = "You won't receive **Stars** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published.";
|
||||
"lng_suggest_warn_text_ton" = "You won't receive **TON** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published.";
|
||||
"lng_suggest_warn_delete_anyway" = "Delete Anyway";
|
||||
"lng_suggest_low_ton_title" = "{amount} TON Needed";
|
||||
"lng_suggest_low_ton_text" = "Buy **TON** to suggest message to {channel} and others.";
|
||||
"lng_suggest_low_ton_fragment" = "Buy on Fragment";
|
||||
"lng_suggest_low_ton_fragment_url" = "https://fragment.com/ads/topup";
|
||||
|
||||
"lng_reply_in_another_title" = "Reply in...";
|
||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||
|
|
|
@ -198,18 +198,8 @@ void SendSuggest(
|
|||
SendSuggest(show, item, state, modify, done, stars);
|
||||
}
|
||||
};
|
||||
const auto checked = state->sendPayment.check(
|
||||
show,
|
||||
item->history()->peer,
|
||||
1,
|
||||
starsApproved,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
const auto isForward = item->Get<HistoryMessageForwarded>();
|
||||
auto action = SendAction(item->history());
|
||||
|
||||
action.options.suggest.exists = 1;
|
||||
if (suggestion) {
|
||||
action.options.suggest.date = suggestion->date;
|
||||
|
@ -218,12 +208,22 @@ void SendSuggest(
|
|||
action.options.suggest.ton = suggestion->price.ton() ? 1 : 0;
|
||||
}
|
||||
modify(action.options.suggest);
|
||||
|
||||
action.options.starsApproved = starsApproved;
|
||||
action.replyTo.monoforumPeerId = item->history()->amMonoforumAdmin()
|
||||
? item->sublistPeerId()
|
||||
: PeerId();
|
||||
action.replyTo.messageId = item->fullId();
|
||||
|
||||
const auto checked = state->sendPayment.check(
|
||||
show,
|
||||
item->history()->peer,
|
||||
action.options,
|
||||
1,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
show->session().api().sendAction(action);
|
||||
show->session().api().forwardMessages({
|
||||
.items = { item },
|
||||
|
@ -302,7 +302,7 @@ void SuggestOfferForMessage(
|
|||
};
|
||||
using namespace HistoryView;
|
||||
auto priceBox = Box(ChooseSuggestPriceBox, SuggestPriceBoxArgs{
|
||||
.session = &show->session(),
|
||||
.peer = item->history()->peer,
|
||||
.done = done,
|
||||
.value = values,
|
||||
.mode = mode,
|
||||
|
|
|
@ -101,8 +101,10 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
friend inline auto operator<=>(CreditsAmount, CreditsAmount) = default;
|
||||
friend inline bool operator==(CreditsAmount, CreditsAmount) = default;
|
||||
friend inline constexpr auto operator<=>(CreditsAmount, CreditsAmount)
|
||||
= default;
|
||||
friend inline constexpr bool operator==(CreditsAmount, CreditsAmount)
|
||||
= default;
|
||||
|
||||
[[nodiscard]] CreditsAmount abs() const {
|
||||
return (_whole < 0) ? CreditsAmount(-_whole, -_nano) : *this;
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "data/components/credits.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_credits.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_app_config.h"
|
||||
|
@ -93,6 +94,54 @@ rpl::producer<CreditsAmount> Credits::balanceValue() const {
|
|||
return _nonLockedBalance.value();
|
||||
}
|
||||
|
||||
void Credits::tonLoad(bool force) {
|
||||
if (_tonRequestId
|
||||
|| (!force
|
||||
&& _tonLastLoaded
|
||||
&& _tonLastLoaded + kReloadThreshold > crl::now())) {
|
||||
return;
|
||||
}
|
||||
_tonRequestId = _session->api().request(MTPpayments_GetStarsStatus(
|
||||
MTP_flags(MTPpayments_GetStarsStatus::Flag::f_ton),
|
||||
MTP_inputPeerSelf()
|
||||
)).done([=](const MTPpayments_StarsStatus &result) {
|
||||
_tonRequestId = 0;
|
||||
const auto amount = CreditsAmountFromTL(result.data().vbalance());
|
||||
if (amount.ton()) {
|
||||
apply(amount);
|
||||
} else if (amount.empty()) {
|
||||
apply(CreditsAmount(0, CreditsType::Ton));
|
||||
} else {
|
||||
LOG(("API Error: Got weird balance."));
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_tonRequestId = 0;
|
||||
LOG(("API Error: Couldn't get TON balance, error: %1"
|
||||
).arg(error.type()));
|
||||
}).send();
|
||||
}
|
||||
|
||||
bool Credits::tonLoaded() const {
|
||||
return _tonLastLoaded != 0;
|
||||
}
|
||||
|
||||
rpl::producer<bool> Credits::tonLoadedValue() const {
|
||||
if (tonLoaded()) {
|
||||
return rpl::single(true);
|
||||
}
|
||||
return rpl::single(
|
||||
false
|
||||
) | rpl::then(_tonLoadedChanges.events() | rpl::map_to(true));
|
||||
}
|
||||
|
||||
CreditsAmount Credits::tonBalance() const {
|
||||
return _tonBalance.current();
|
||||
}
|
||||
|
||||
rpl::producer<CreditsAmount> Credits::tonBalanceValue() const {
|
||||
return _tonBalance.value();
|
||||
}
|
||||
|
||||
void Credits::updateNonLockedValue() {
|
||||
_nonLockedBalance = (_balance >= _locked)
|
||||
? (_balance - _locked)
|
||||
|
@ -133,7 +182,12 @@ void Credits::invalidate() {
|
|||
|
||||
void Credits::apply(CreditsAmount balance) {
|
||||
if (balance.ton()) {
|
||||
_balanceTon = balance;
|
||||
_tonBalance = balance;
|
||||
|
||||
const auto was = std::exchange(_tonLastLoaded, crl::now());
|
||||
if (!was) {
|
||||
_tonLoadedChanges.fire({});
|
||||
}
|
||||
} else {
|
||||
_balance = balance;
|
||||
updateNonLockedValue();
|
||||
|
|
|
@ -19,12 +19,8 @@ public:
|
|||
~Credits();
|
||||
|
||||
void load(bool force = false);
|
||||
void apply(CreditsAmount balance);
|
||||
void apply(PeerId peerId, CreditsAmount balance);
|
||||
|
||||
[[nodiscard]] bool loaded() const;
|
||||
[[nodiscard]] rpl::producer<bool> loadedValue() const;
|
||||
|
||||
[[nodiscard]] CreditsAmount balance() const;
|
||||
[[nodiscard]] CreditsAmount balance(PeerId peerId) const;
|
||||
[[nodiscard]] rpl::producer<CreditsAmount> balanceValue() const;
|
||||
|
@ -33,6 +29,15 @@ public:
|
|||
|
||||
[[nodiscard]] rpl::producer<> refreshedByPeerId(PeerId peerId);
|
||||
|
||||
void tonLoad(bool force = false);
|
||||
[[nodiscard]] bool tonLoaded() const;
|
||||
[[nodiscard]] rpl::producer<bool> tonLoadedValue() const;
|
||||
[[nodiscard]] CreditsAmount tonBalance() const;
|
||||
[[nodiscard]] rpl::producer<CreditsAmount> tonBalanceValue() const;
|
||||
|
||||
void apply(CreditsAmount balance);
|
||||
void apply(PeerId peerId, CreditsAmount balance);
|
||||
|
||||
[[nodiscard]] bool statsEnabled() const;
|
||||
|
||||
void applyCurrency(PeerId peerId, uint64 balance);
|
||||
|
@ -56,13 +61,17 @@ private:
|
|||
base::flat_map<PeerId, uint64> _cachedPeerCurrencyBalances;
|
||||
|
||||
CreditsAmount _balance;
|
||||
CreditsAmount _balanceTon;
|
||||
CreditsAmount _locked;
|
||||
rpl::variable<CreditsAmount> _nonLockedBalance;
|
||||
rpl::event_stream<> _loadedChanges;
|
||||
crl::time _lastLoaded = 0;
|
||||
float64 _rate = 0.;
|
||||
|
||||
rpl::variable<CreditsAmount> _tonBalance;
|
||||
rpl::event_stream<> _tonLoadedChanges;
|
||||
crl::time _tonLastLoaded = false;
|
||||
mtpRequestId _tonRequestId = 0;
|
||||
|
||||
bool _statsEnabled = false;
|
||||
|
||||
rpl::event_stream<PeerId> _refreshedByPeerId;
|
||||
|
|
|
@ -1262,7 +1262,9 @@ void ApplyChannelUpdate(
|
|||
| Flag::PaidMediaAllowed
|
||||
| Flag::CanViewCreditsRevenue
|
||||
| Flag::StargiftsAvailable
|
||||
| Flag::PaidMessagesAvailable;
|
||||
| Flag::PaidMessagesAvailable
|
||||
| Flag::HasStarsPerMessage
|
||||
| Flag::StarsPerMessageKnown;
|
||||
channel->setFlags((channel->flags() & ~mask)
|
||||
| (update.is_can_set_username() ? Flag::CanSetUsername : Flag())
|
||||
| (update.is_can_view_participants()
|
||||
|
@ -1289,7 +1291,9 @@ void ApplyChannelUpdate(
|
|||
: Flag())
|
||||
| (update.is_paid_messages_available()
|
||||
? Flag::PaidMessagesAvailable
|
||||
: Flag()));
|
||||
: Flag())
|
||||
| (channel->starsPerMessage() ? Flag::HasStarsPerMessage : Flag())
|
||||
| Flag::StarsPerMessageKnown);
|
||||
channel->setUserpicPhoto(update.vchat_photo());
|
||||
if (const auto migratedFrom = update.vmigrated_from_chat_id()) {
|
||||
channel->addFlags(Flag::Megagroup);
|
||||
|
|
|
@ -83,6 +83,8 @@ enum class ChannelDataFlag : uint64 {
|
|||
MonoforumAdmin = (1ULL << 40),
|
||||
MonoforumDisabled = (1ULL << 41),
|
||||
ForumTabs = (1ULL << 42),
|
||||
HasStarsPerMessage = (1ULL << 43),
|
||||
StarsPerMessageKnown = (1ULL << 44),
|
||||
};
|
||||
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
|
||||
using ChannelDataFlags = base::flags<ChannelDataFlag>;
|
||||
|
@ -280,6 +282,12 @@ public:
|
|||
[[nodiscard]] bool paidMessagesAvailable() const {
|
||||
return flags() & Flag::PaidMessagesAvailable;
|
||||
}
|
||||
[[nodiscard]] bool hasStarsPerMessage() const {
|
||||
return flags() & Flag::HasStarsPerMessage;
|
||||
}
|
||||
[[nodiscard]] bool starsPerMessageKnown() const {
|
||||
return flags() & Flag::StarsPerMessageKnown;
|
||||
}
|
||||
[[nodiscard]] bool useSubsectionTabs() const;
|
||||
|
||||
[[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights(
|
||||
|
|
|
@ -992,7 +992,14 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
? Flag::StoriesHidden
|
||||
: Flag())
|
||||
| Flag::AutoTranslation
|
||||
| Flag::Monoforum;
|
||||
| Flag::Monoforum
|
||||
| Flag::HasStarsPerMessage
|
||||
| Flag::StarsPerMessageKnown;
|
||||
const auto hasStarsPerMessage
|
||||
= data.vsend_paid_messages_stars().has_value();
|
||||
if (!hasStarsPerMessage) {
|
||||
channel->setStarsPerMessage(0);
|
||||
}
|
||||
const auto storiesState = minimal
|
||||
? std::optional<Data::Stories::PeerSourceState>()
|
||||
: data.is_stories_unavailable()
|
||||
|
@ -1034,7 +1041,13 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
? Flag::StoriesHidden
|
||||
: Flag())
|
||||
| (data.is_autotranslation() ? Flag::AutoTranslation : Flag())
|
||||
| (data.is_monoforum() ? Flag::Monoforum : Flag());
|
||||
| (data.is_monoforum() ? Flag::Monoforum : Flag())
|
||||
| (hasStarsPerMessage
|
||||
? (Flag::HasStarsPerMessage
|
||||
| (channel->starsPerMessageKnown()
|
||||
? Flag::StarsPerMessageKnown
|
||||
: Flag()))
|
||||
: Flag::StarsPerMessageKnown);
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
channel->setBotVerifyDetailsIcon(
|
||||
data.vbot_verification_icon().value_or_empty());
|
||||
|
@ -1047,12 +1060,6 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
}
|
||||
|
||||
channel->setPhoto(data.vphoto());
|
||||
const auto hasStarsPerMessage
|
||||
= data.vsend_paid_messages_stars().has_value();
|
||||
if (!hasStarsPerMessage) {
|
||||
channel->setStarsPerMessage(0);
|
||||
}
|
||||
|
||||
if (const auto monoforum = data.vlinked_monoforum_id()) {
|
||||
if (const auto linked = channelLoaded(monoforum->v)) {
|
||||
channel->setMonoforumLink(linked);
|
||||
|
|
|
@ -719,6 +719,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
|||
| Flag::CanPinMessages
|
||||
| Flag::VoiceMessagesForbidden
|
||||
| Flag::ReadDatesPrivate
|
||||
| Flag::HasStarsPerMessage
|
||||
| Flag::MessageMoneyRestrictionsKnown
|
||||
| Flag::RequiresPremiumToWrite;
|
||||
user->setFlags((user->flags() & ~mask)
|
||||
|
@ -732,6 +733,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
|||
? Flag::VoiceMessagesForbidden
|
||||
: Flag())
|
||||
| (update.is_read_dates_private() ? Flag::ReadDatesPrivate : Flag())
|
||||
| (user->starsPerMessage() ? Flag::HasStarsPerMessage : Flag())
|
||||
| Flag::MessageMoneyRestrictionsKnown
|
||||
| (update.is_contact_require_premium()
|
||||
? Flag::RequiresPremiumToWrite
|
||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/view/controls/history_view_suggest_options.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "main/main_account.h"
|
||||
|
@ -189,20 +190,27 @@ Data::SendErrorWithThread GetErrorForSending(
|
|||
std::optional<SendPaymentDetails> ComputePaymentDetails(
|
||||
not_null<PeerData*> peer,
|
||||
int messagesCount) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->hasStarsPerMessage()
|
||||
&& !user->messageMoneyRestrictionsKnown()) {
|
||||
user->updateFull();
|
||||
return {};
|
||||
}
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
if (!channel->isFullLoaded()) {
|
||||
channel->updateFull();
|
||||
return {};
|
||||
}
|
||||
const auto user = peer->asUser();
|
||||
const auto channel = user ? nullptr : peer->asChannel();
|
||||
const auto has = (user && user->hasStarsPerMessage())
|
||||
|| (channel && channel->hasStarsPerMessage());
|
||||
if (!has) {
|
||||
return SendPaymentDetails();
|
||||
}
|
||||
if (!peer->session().credits().loaded()) {
|
||||
|
||||
const auto known1 = peer->session().credits().loaded();
|
||||
if (!known1) {
|
||||
peer->session().credits().load();
|
||||
}
|
||||
|
||||
const auto known2 = user
|
||||
? user->messageMoneyRestrictionsKnown()
|
||||
: channel->starsPerMessageKnown();
|
||||
if (!known2) {
|
||||
peer->updateFull();
|
||||
}
|
||||
|
||||
if (!known1 || !known2) {
|
||||
return {};
|
||||
} else if (const auto perMessage = peer->starsPerMessageChecked()) {
|
||||
return SendPaymentDetails{
|
||||
|
@ -213,6 +221,21 @@ std::optional<SendPaymentDetails> ComputePaymentDetails(
|
|||
return SendPaymentDetails();
|
||||
}
|
||||
|
||||
bool SuggestPaymentDataReady(
|
||||
not_null<PeerData*> peer,
|
||||
SuggestPostOptions suggest) {
|
||||
if (!suggest.exists || !suggest.price()) {
|
||||
return true;
|
||||
} else if (suggest.ton && !peer->session().credits().tonLoaded()) {
|
||||
peer->session().credits().tonLoad();
|
||||
return false;
|
||||
} else if (!suggest.ton && !peer->session().credits().loaded()) {
|
||||
peer->session().credits().load();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
object_ptr<Ui::BoxContent> MakeSendErrorBox(
|
||||
const Data::SendErrorWithThread &error,
|
||||
bool withTitle) {
|
||||
|
@ -250,13 +273,15 @@ void ShowSendPaidConfirm(
|
|||
not_null<PeerData*> peer,
|
||||
SendPaymentDetails details,
|
||||
Fn<void()> confirmed,
|
||||
PaidConfirmStyles styles) {
|
||||
PaidConfirmStyles styles,
|
||||
int suggestStarsPrice) {
|
||||
return ShowSendPaidConfirm(
|
||||
navigation->uiShow(),
|
||||
peer,
|
||||
details,
|
||||
confirmed,
|
||||
styles);
|
||||
styles,
|
||||
suggestStarsPrice);
|
||||
}
|
||||
|
||||
void ShowSendPaidConfirm(
|
||||
|
@ -264,13 +289,15 @@ void ShowSendPaidConfirm(
|
|||
not_null<PeerData*> peer,
|
||||
SendPaymentDetails details,
|
||||
Fn<void()> confirmed,
|
||||
PaidConfirmStyles styles) {
|
||||
PaidConfirmStyles styles,
|
||||
int suggestStarsPrice) {
|
||||
ShowSendPaidConfirm(
|
||||
std::move(show),
|
||||
std::vector<not_null<PeerData*>>{ peer },
|
||||
details,
|
||||
confirmed,
|
||||
styles);
|
||||
styles,
|
||||
suggestStarsPrice);
|
||||
}
|
||||
|
||||
void ShowSendPaidConfirm(
|
||||
|
@ -278,7 +305,8 @@ void ShowSendPaidConfirm(
|
|||
const std::vector<not_null<PeerData*>> &peers,
|
||||
SendPaymentDetails details,
|
||||
Fn<void()> confirmed,
|
||||
PaidConfirmStyles styles) {
|
||||
PaidConfirmStyles styles,
|
||||
int suggestStarsPrice) {
|
||||
Expects(!peers.empty());
|
||||
|
||||
const auto singlePeer = (peers.size() > 1)
|
||||
|
@ -286,7 +314,7 @@ void ShowSendPaidConfirm(
|
|||
: peers.front().get();
|
||||
const auto singlePeerId = singlePeer ? singlePeer->id : PeerId();
|
||||
const auto check = [=] {
|
||||
const auto required = details.stars;
|
||||
const auto required = details.stars + suggestStarsPrice;
|
||||
if (!required) {
|
||||
return;
|
||||
}
|
||||
|
@ -296,10 +324,13 @@ void ShowSendPaidConfirm(
|
|||
confirmed();
|
||||
}
|
||||
};
|
||||
Settings::MaybeRequestBalanceIncrease(
|
||||
using namespace Settings;
|
||||
MaybeRequestBalanceIncrease(
|
||||
show,
|
||||
required,
|
||||
Settings::SmallBalanceForMessage{ .recipientId = singlePeerId },
|
||||
(suggestStarsPrice
|
||||
? SmallBalanceSource(SmallBalanceForSuggest{ singlePeerId })
|
||||
: SmallBalanceForMessage{ singlePeerId }),
|
||||
done);
|
||||
};
|
||||
auto usersOnly = true;
|
||||
|
@ -388,15 +419,15 @@ void ShowSendPaidConfirm(
|
|||
bool SendPaymentHelper::check(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer,
|
||||
Api::SendOptions options,
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Fn<void(int)> resend,
|
||||
PaidConfirmStyles styles) {
|
||||
return check(
|
||||
navigation->uiShow(),
|
||||
peer,
|
||||
options,
|
||||
messagesCount,
|
||||
starsApproved,
|
||||
std::move(resend),
|
||||
styles);
|
||||
}
|
||||
|
@ -404,17 +435,27 @@ bool SendPaymentHelper::check(
|
|||
bool SendPaymentHelper::check(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<PeerData*> peer,
|
||||
Api::SendOptions options,
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Fn<void(int)> resend,
|
||||
PaidConfirmStyles styles) {
|
||||
clear();
|
||||
|
||||
const auto suggest = options.suggest;
|
||||
const auto starsApproved = options.starsApproved;
|
||||
const auto suggestPriceStars = suggest.ton
|
||||
? 0
|
||||
: int(base::SafeRound(suggest.price().value()));
|
||||
const auto suggestPriceTon = suggest.ton
|
||||
? suggest.price()
|
||||
: CreditsAmount();
|
||||
const auto details = ComputePaymentDetails(peer, messagesCount);
|
||||
if (!details) {
|
||||
const auto suggestDetails = SuggestPaymentDataReady(peer, suggest);
|
||||
if (!details || !suggestDetails) {
|
||||
_resend = [=] { resend(starsApproved); };
|
||||
|
||||
if (!peer->session().credits().loaded()) {
|
||||
if ((!details || !suggest.ton)
|
||||
&& !peer->session().credits().loaded()) {
|
||||
peer->session().credits().loadedValue(
|
||||
) | rpl::filter(
|
||||
rpl::mappers::_1
|
||||
|
@ -425,6 +466,18 @@ bool SendPaymentHelper::check(
|
|||
}, _lifetime);
|
||||
}
|
||||
|
||||
if ((!suggestDetails && suggest.ton)
|
||||
&& !peer->session().credits().tonLoaded()) {
|
||||
peer->session().credits().tonLoadedValue(
|
||||
) | 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
|
||||
|
@ -438,7 +491,32 @@ bool SendPaymentHelper::check(
|
|||
} else if (const auto stars = details->stars; stars > starsApproved) {
|
||||
ShowSendPaidConfirm(show, peer, *details, [=] {
|
||||
resend(stars);
|
||||
}, styles);
|
||||
}, styles, suggestPriceStars);
|
||||
return false;
|
||||
} else if (suggestPriceStars
|
||||
&& (CreditsAmount(details->stars + suggestPriceStars)
|
||||
> peer->session().credits().balance())) {
|
||||
const auto peerId = peer->id;
|
||||
const auto forMessages = details->stars;
|
||||
const auto required = forMessages + suggestPriceStars;
|
||||
const auto done = [=](Settings::SmallBalanceResult result) {
|
||||
if (result == Settings::SmallBalanceResult::Success
|
||||
|| result == Settings::SmallBalanceResult::Already) {
|
||||
resend(forMessages);
|
||||
}
|
||||
};
|
||||
using namespace Settings;
|
||||
MaybeRequestBalanceIncrease(
|
||||
show,
|
||||
required,
|
||||
SmallBalanceForSuggest{ peerId },
|
||||
done);
|
||||
return false;
|
||||
}
|
||||
if (suggestPriceTon
|
||||
&& suggestPriceTon > peer->session().credits().tonBalance()) {
|
||||
show->show(
|
||||
Box(HistoryView::InsufficientTonBox, peer, suggestPriceTon));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -149,6 +149,10 @@ struct SendPaymentDetails {
|
|||
not_null<PeerData*> peer,
|
||||
int messagesCount);
|
||||
|
||||
[[nodiscard]] bool SuggestPaymentDataReady(
|
||||
not_null<PeerData*> peer,
|
||||
SuggestPostOptions suggest);
|
||||
|
||||
struct PaidConfirmStyles {
|
||||
const style::FlatLabel *label = nullptr;
|
||||
const style::Checkbox *checkbox = nullptr;
|
||||
|
@ -158,34 +162,37 @@ void ShowSendPaidConfirm(
|
|||
not_null<PeerData*> peer,
|
||||
SendPaymentDetails details,
|
||||
Fn<void()> confirmed,
|
||||
PaidConfirmStyles styles = {});
|
||||
PaidConfirmStyles styles = {},
|
||||
int suggestStarsPrice = 0);
|
||||
void ShowSendPaidConfirm(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<PeerData*> peer,
|
||||
SendPaymentDetails details,
|
||||
Fn<void()> confirmed,
|
||||
PaidConfirmStyles styles = {});
|
||||
PaidConfirmStyles styles = {},
|
||||
int suggestStarsPrice = 0);
|
||||
void ShowSendPaidConfirm(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
const std::vector<not_null<PeerData*>> &peers,
|
||||
SendPaymentDetails details,
|
||||
Fn<void()> confirmed,
|
||||
PaidConfirmStyles styles = {});
|
||||
PaidConfirmStyles styles = {},
|
||||
int suggestStarsPrice = 0);
|
||||
|
||||
class SendPaymentHelper final {
|
||||
public:
|
||||
[[nodiscard]] bool check(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer,
|
||||
Api::SendOptions options,
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Fn<void(int)> resend,
|
||||
PaidConfirmStyles styles = {});
|
||||
[[nodiscard]] bool check(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<PeerData*> peer,
|
||||
Api::SendOptions options,
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Fn<void(int)> resend,
|
||||
PaidConfirmStyles styles = {});
|
||||
|
||||
|
|
|
@ -4540,7 +4540,7 @@ void HistoryWidget::saveEditMessage(Api::SendOptions options) {
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1 + int(_forwardPanel->items().size()),
|
||||
options.starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -4629,15 +4629,15 @@ void HistoryWidget::sendVoice(const VoiceToSend &data) {
|
|||
copy.options.starsApproved = approved;
|
||||
sendVoice(copy);
|
||||
};
|
||||
auto action = prepareSendAction(data.options);
|
||||
const auto checked = checkSendPayment(
|
||||
1 + int(_forwardPanel->items().size()),
|
||||
data.options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = prepareSendAction(data.options);
|
||||
session().api().sendVoiceMessage(
|
||||
data.bytes,
|
||||
data.waveform,
|
||||
|
@ -4678,7 +4678,7 @@ void HistoryWidget::send(Api::SendOptions options) {
|
|||
message.textWithTags,
|
||||
ignoreSlowmodeCountdown,
|
||||
withPaymentApproved,
|
||||
options.starsApproved)) {
|
||||
message.action.options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5011,14 +5011,14 @@ FullMsgId HistoryWidget::cornerButtonsCurrentId() {
|
|||
|
||||
bool HistoryWidget::checkSendPayment(
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Api::SendOptions options,
|
||||
Fn<void(int)> withPaymentApproved) {
|
||||
return _peer
|
||||
&& _sendPayment.check(
|
||||
controller(),
|
||||
_peer,
|
||||
options,
|
||||
messagesCount,
|
||||
starsApproved,
|
||||
std::move(withPaymentApproved));
|
||||
}
|
||||
|
||||
|
@ -5209,9 +5209,11 @@ void HistoryWidget::sendBotCommand(
|
|||
copy.starsApproved = approved;
|
||||
sendBotCommand(request, copy);
|
||||
};
|
||||
|
||||
const auto action = prepareSendAction(options);
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -5226,7 +5228,7 @@ void HistoryWidget::sendBotCommand(
|
|||
? request.command
|
||||
: Bot::WrapCommandInChat(_peer, request.command, request.context);
|
||||
|
||||
auto message = Api::MessageToSend(prepareSendAction(options));
|
||||
auto message = Api::MessageToSend(action);
|
||||
message.textWithTags = { toSend, TextWithTags::Tags() };
|
||||
message.action.replyTo = request.replyTo
|
||||
? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/)
|
||||
|
@ -6233,7 +6235,7 @@ bool HistoryWidget::showSendMessageError(
|
|||
const TextWithTags &textWithTags,
|
||||
bool ignoreSlowmodeCountdown,
|
||||
Fn<void(int starsApproved)> withPaymentApproved,
|
||||
int starsApproved) {
|
||||
Api::SendOptions options) {
|
||||
if (!_canSendMessages) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6254,7 +6256,7 @@ bool HistoryWidget::showSendMessageError(
|
|||
return withPaymentApproved
|
||||
&& !checkSendPayment(
|
||||
request.messagesCount,
|
||||
starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
}
|
||||
|
||||
|
@ -6369,6 +6371,11 @@ void HistoryWidget::sendingFilesConfirmed(
|
|||
void HistoryWidget::sendingFilesConfirmed(
|
||||
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||
Api::SendOptions options) {
|
||||
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||
auto action = prepareSendAction(options);
|
||||
action.clearDraft = false;
|
||||
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
copy.starsApproved = approved;
|
||||
|
@ -6376,16 +6383,12 @@ void HistoryWidget::sendingFilesConfirmed(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
bundle->totalCount,
|
||||
options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||
auto action = prepareSendAction(options);
|
||||
action.clearDraft = false;
|
||||
if (bundle->sendComment) {
|
||||
auto message = Api::MessageToSend(action);
|
||||
message.textWithTags = base::take(bundle->caption);
|
||||
|
@ -7715,9 +7718,13 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
|
|||
copy.options.starsApproved = approved;
|
||||
sendInlineResult(copy);
|
||||
};
|
||||
|
||||
auto action = prepareSendAction(result.options);
|
||||
action.generateLocal = true;
|
||||
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
result.options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -7725,9 +7732,6 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
|
|||
|
||||
controller()->sendingAnimation().appendSending(
|
||||
result.messageSendingFrom);
|
||||
|
||||
auto action = prepareSendAction(result.options);
|
||||
action.generateLocal = true;
|
||||
session().api().sendInlineResult(
|
||||
result.bot,
|
||||
result.result.get(),
|
||||
|
@ -8336,7 +8340,7 @@ bool HistoryWidget::sendExistingDocument(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
messageToSend.action.options.starsApproved,
|
||||
messageToSend.action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
|
@ -8375,6 +8379,7 @@ bool HistoryWidget::sendExistingPhoto(
|
|||
} else if (showSlowmodeError()) {
|
||||
return false;
|
||||
}
|
||||
const auto action = prepareSendAction(options);
|
||||
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
|
@ -8383,15 +8388,13 @@ bool HistoryWidget::sendExistingPhoto(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Api::SendExistingPhoto(
|
||||
Api::MessageToSend(prepareSendAction(options)),
|
||||
photo);
|
||||
Api::SendExistingPhoto(Api::MessageToSend(action), photo);
|
||||
|
||||
hideSelectorControlsAnimated();
|
||||
|
||||
|
|
|
@ -371,7 +371,7 @@ private:
|
|||
|
||||
[[nodiscard]] bool checkSendPayment(
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Api::SendOptions options,
|
||||
Fn<void(int)> withPaymentApproved);
|
||||
|
||||
void checkSuggestToGigagroup();
|
||||
|
@ -489,7 +489,7 @@ private:
|
|||
const TextWithTags &textWithTags,
|
||||
bool ignoreSlowmodeCountdown,
|
||||
Fn<void(int starsApproved)> withPaymentApproved = nullptr,
|
||||
int starsApproved = 0);
|
||||
Api::SendOptions options = {});
|
||||
|
||||
void sendingFilesConfirmed(
|
||||
Ui::PreparedList &&list,
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/unixtime.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/components/credits.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_media_types.h"
|
||||
|
@ -19,9 +20,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_item_components.h"
|
||||
#include "info/channel_statistics/earn/earn_icons.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "lottie/lottie_icon.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/boxes/choose_date_time.h"
|
||||
|
@ -30,8 +33,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/basic_click_handlers.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_channel_earn.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
@ -81,13 +87,19 @@ void ChooseSuggestPriceBox(
|
|||
std::vector<Button> buttons;
|
||||
rpl::variable<TimeId> date;
|
||||
rpl::variable<bool> ton;
|
||||
Fn<void()> save;
|
||||
bool savePending = false;
|
||||
bool inButton = false;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->date = args.value.date;
|
||||
state->ton = (args.value.ton != 0);
|
||||
|
||||
const auto limit = args.session->appConfig().suggestedPostStarsMax();
|
||||
const auto peer = args.peer;
|
||||
const auto session = &peer->session();
|
||||
session->credits().load();
|
||||
session->credits().tonLoad();
|
||||
const auto limit = session->appConfig().suggestedPostStarsMax();
|
||||
|
||||
box->setTitle((args.mode == SuggestMode::New)
|
||||
? tr::lng_suggest_options_title()
|
||||
|
@ -196,7 +208,7 @@ void ChooseSuggestPriceBox(
|
|||
Ui::AddSkip(container);
|
||||
|
||||
const auto added = st::boxRowPadding - st::defaultSubsectionTitlePadding;
|
||||
const auto manager = &args.session->data().customEmojiManager();
|
||||
const auto manager = &session->data().customEmojiManager();
|
||||
const auto makeIcon = [&](
|
||||
not_null<QWidget*> parent,
|
||||
TextWithEntities text) {
|
||||
|
@ -205,7 +217,7 @@ void ChooseSuggestPriceBox(
|
|||
rpl::single(text),
|
||||
st::defaultFlatLabel,
|
||||
st::defaultPopupMenu,
|
||||
Core::TextContext({ .session = args.session }));
|
||||
Core::TextContext({ .session = session }));
|
||||
};
|
||||
|
||||
const auto starsWrap = container->add(
|
||||
|
@ -333,7 +345,7 @@ void ChooseSuggestPriceBox(
|
|||
}
|
||||
};
|
||||
auto dateBox = Box(ChooseSuggestTimeBox, SuggestTimeBoxArgs{
|
||||
.session = args.session,
|
||||
.session = session,
|
||||
.done = done,
|
||||
.value = state->date.current(),
|
||||
.mode = args.mode,
|
||||
|
@ -344,8 +356,8 @@ void ChooseSuggestPriceBox(
|
|||
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDividerText(container, tr::lng_suggest_options_date_about());
|
||||
AssertIsDebug()//tr::lng_suggest_options_offer
|
||||
const auto save = [=] {
|
||||
AssertIsDebug();//tr::lng_suggest_options_offer
|
||||
state->save = [=] {
|
||||
auto nanos = int64();
|
||||
if (state->ton.current()) {
|
||||
const auto now = Ui::ParseTonAmountString(
|
||||
|
@ -363,22 +375,74 @@ void ChooseSuggestPriceBox(
|
|||
}
|
||||
nanos = now * Ui::kNanosInOne;
|
||||
}
|
||||
const auto ton = uint32(state->ton.current() ? 1 : 0);
|
||||
const auto value = CreditsAmount(
|
||||
nanos / Ui::kNanosInOne,
|
||||
nanos % Ui::kNanosInOne);
|
||||
nanos % Ui::kNanosInOne,
|
||||
ton ? CreditsType::Ton : CreditsType::Stars);
|
||||
const auto credits = &session->credits();
|
||||
if (ton) {
|
||||
if (!credits->tonLoaded()) {
|
||||
state->savePending = true;
|
||||
return;
|
||||
} else if (credits->tonBalance() < value) {
|
||||
box->uiShow()->show(
|
||||
Box(InsufficientTonBox, peer, value));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!credits->loaded()) {
|
||||
state->savePending = true;
|
||||
return;
|
||||
}
|
||||
using namespace Settings;
|
||||
const auto required = peer->starsPerMessageChecked()
|
||||
+ int(base::SafeRound(value.value()));
|
||||
const auto done = [=](SmallBalanceResult result) {
|
||||
if (result == SmallBalanceResult::Success
|
||||
|| result == SmallBalanceResult::Already) {
|
||||
state->save();
|
||||
}
|
||||
};
|
||||
MaybeRequestBalanceIncrease(
|
||||
Main::MakeSessionShow(box->uiShow(), session),
|
||||
required,
|
||||
SmallBalanceForSuggest{ peer->id },
|
||||
done);
|
||||
return;
|
||||
}
|
||||
state->save = nullptr;
|
||||
args.done({
|
||||
.exists = true,
|
||||
.priceWhole = uint32(value.whole()),
|
||||
.priceNano = uint32(value.nano()),
|
||||
.ton = uint32(state->ton.current() ? 1 : 0),
|
||||
.ton = ton,
|
||||
.date = state->date.current(),
|
||||
});
|
||||
};
|
||||
|
||||
QObject::connect(starsField, &Ui::NumberInput::submitted, box, save);
|
||||
tonField->submits() | rpl::start_with_next(save, tonField->lifetime());
|
||||
const auto credits = &session->credits();
|
||||
rpl::combine(
|
||||
credits->tonBalanceValue(),
|
||||
credits->balanceValue()
|
||||
) | rpl::filter([=] {
|
||||
return state->savePending;
|
||||
}) | rpl::start_with_next([=] {
|
||||
state->savePending = false;
|
||||
if (const auto onstack = state->save) {
|
||||
onstack();
|
||||
}
|
||||
}, box->lifetime());
|
||||
|
||||
box->addButton(tr::lng_settings_save(), save);
|
||||
QObject::connect(
|
||||
starsField,
|
||||
&Ui::NumberInput::submitted,
|
||||
box,
|
||||
state->save);
|
||||
tonField->submits(
|
||||
) | rpl::start_with_next(state->save, tonField->lifetime());
|
||||
|
||||
box->addButton(tr::lng_settings_save(), state->save);
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
|
@ -402,6 +466,52 @@ bool CanAddOfferToMessage(not_null<HistoryItem*> item) {
|
|||
history->owner().history(broadcast)).has_value();
|
||||
}
|
||||
|
||||
void InsufficientTonBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<PeerData*> peer,
|
||||
CreditsAmount required) {
|
||||
auto icon = Settings::CreateLottieIcon(
|
||||
box->verticalLayout(),
|
||||
{
|
||||
.name = u"diamond"_q,
|
||||
.sizeOverride = Size(st::changePhoneIconSize),
|
||||
},
|
||||
{});
|
||||
box->setShowFinishedCallback([animate = std::move(icon.animate)] {
|
||||
animate(anim::repeat::loop);
|
||||
});
|
||||
box->addRow(std::move(icon.widget), st::lowTonIconPadding);
|
||||
const auto add = required - peer->session().credits().tonBalance();
|
||||
const auto nano = add.whole() * Ui::kNanosInOne + add.nano();
|
||||
const auto amount = Ui::FormatTonAmount(nano).full;
|
||||
box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_suggest_low_ton_title(tr::now, lt_amount, amount),
|
||||
st::boxTitle)),
|
||||
st::boxRowPadding + st::lowTonTitlePadding);
|
||||
const auto label = box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_suggest_low_ton_text(
|
||||
lt_channel,
|
||||
rpl::single(Ui::Text::Bold(peer->name())),
|
||||
Ui::Text::RichLangValue),
|
||||
st::lowTonText),
|
||||
st::boxRowPadding + st::lowTonTextPadding);
|
||||
label->setTryMakeSimilarLines(true);
|
||||
label->resizeToWidth(
|
||||
st::boxWidth - st::boxRowPadding.left() - st::boxRowPadding.right());
|
||||
box->addButton(tr::lng_suggest_low_ton_fragment(), [=] {
|
||||
UrlClickHandler::Open(tr::lng_suggest_low_ton_fragment_url(tr::now));
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
}
|
||||
|
||||
SuggestOptions::SuggestOptions(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -458,7 +568,7 @@ void SuggestOptions::edit() {
|
|||
}
|
||||
};
|
||||
*weak = _show->show(Box(ChooseSuggestPriceBox, SuggestPriceBoxArgs{
|
||||
.session = &_peer->session(),
|
||||
.peer = _peer,
|
||||
.done = apply,
|
||||
.value = _values,
|
||||
}));
|
||||
|
|
|
@ -44,7 +44,7 @@ void ChooseSuggestTimeBox(
|
|||
SuggestTimeBoxArgs &&args);
|
||||
|
||||
struct SuggestPriceBoxArgs {
|
||||
not_null<Main::Session*> session;
|
||||
not_null<PeerData*> peer;
|
||||
bool updating = false;
|
||||
Fn<void(SuggestPostOptions)> done;
|
||||
SuggestPostOptions value;
|
||||
|
@ -58,6 +58,11 @@ void ChooseSuggestPriceBox(
|
|||
|
||||
[[nodiscard]] bool CanAddOfferToMessage(not_null<HistoryItem*> item);
|
||||
|
||||
void InsufficientTonBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<PeerData*> peer,
|
||||
CreditsAmount required);
|
||||
|
||||
class SuggestOptions final {
|
||||
public:
|
||||
SuggestOptions(
|
||||
|
|
|
@ -1195,13 +1195,13 @@ void ChatWidget::sendingFilesConfirmed(
|
|||
|
||||
bool ChatWidget::checkSendPayment(
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Api::SendOptions options,
|
||||
Fn<void(int)> withPaymentApproved) {
|
||||
return _sendPayment.check(
|
||||
controller(),
|
||||
_peer,
|
||||
options,
|
||||
messagesCount,
|
||||
starsApproved,
|
||||
std::move(withPaymentApproved));
|
||||
}
|
||||
|
||||
|
@ -1215,7 +1215,7 @@ void ChatWidget::sendingFilesConfirmed(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
bundle->totalCount,
|
||||
options.starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -1386,7 +1386,7 @@ void ChatWidget::sendVoice(const ComposeControls::VoiceToSend &data) {
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
data.options.starsApproved,
|
||||
data.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -1438,7 +1438,7 @@ void ChatWidget::send(Api::SendOptions options) {
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
request.messagesCount,
|
||||
options.starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -1669,7 +1669,7 @@ bool ChatWidget::sendExistingDocument(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
messageToSend.action.options.starsApproved,
|
||||
messageToSend.action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
|
@ -1709,7 +1709,7 @@ bool ChatWidget::sendExistingPhoto(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
|
@ -1752,7 +1752,7 @@ void ChatWidget::sendInlineResult(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -3158,7 +3158,7 @@ void ChatWidget::sendBotCommandWithOptions(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
|
|
@ -227,7 +227,7 @@ private:
|
|||
|
||||
[[nodiscard]] bool checkSendPayment(
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Api::SendOptions options,
|
||||
Fn<void(int)> withPaymentApproved);
|
||||
|
||||
void markLoaded();
|
||||
|
|
|
@ -1910,8 +1910,8 @@ void WebViewInstance::botSendPreparedMessage(
|
|||
const auto checked = state->sendPayment.check(
|
||||
uiShow(),
|
||||
strong->peer(),
|
||||
options,
|
||||
1,
|
||||
options.starsApproved,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -2545,8 +2545,8 @@ void ChooseAndSendLocation(
|
|||
const auto checked = state->sendPayment.check(
|
||||
strong,
|
||||
action.history->peer,
|
||||
action.options,
|
||||
1,
|
||||
action.options.starsApproved,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
|
|
@ -257,7 +257,7 @@ bool ReplyArea::send(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
request.messagesCount,
|
||||
message.action.options.starsApproved,
|
||||
message.action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
|
@ -273,7 +273,7 @@ bool ReplyArea::send(
|
|||
|
||||
bool ReplyArea::checkSendPayment(
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Api::SendOptions options,
|
||||
Fn<void(int)> withPaymentApproved) {
|
||||
const auto st1 = ::Settings::DarkCreditsEntryBoxStyle();
|
||||
const auto st2 = st1.shareBox.get();
|
||||
|
@ -282,8 +282,8 @@ bool ReplyArea::checkSendPayment(
|
|||
&& _sendPayment.check(
|
||||
_controller->uiShow(),
|
||||
_data.peer,
|
||||
options,
|
||||
messagesCount,
|
||||
starsApproved,
|
||||
std::move(withPaymentApproved),
|
||||
{
|
||||
.label = st3 ? st3->chooseDateTimeArgs.labelStyle : nullptr,
|
||||
|
@ -292,6 +292,8 @@ bool ReplyArea::checkSendPayment(
|
|||
}
|
||||
|
||||
void ReplyArea::sendVoice(const VoiceToSend &data) {
|
||||
auto action = prepareSendAction(data.options);
|
||||
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = data;
|
||||
copy.options.starsApproved = approved;
|
||||
|
@ -299,13 +301,12 @@ void ReplyArea::sendVoice(const VoiceToSend &data) {
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
data.options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = prepareSendAction(data.options);
|
||||
session().api().sendVoiceMessage(
|
||||
data.bytes,
|
||||
data.waveform,
|
||||
|
@ -341,7 +342,7 @@ bool ReplyArea::sendExistingDocument(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
messageToSend.action.options.starsApproved,
|
||||
messageToSend.action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
|
@ -373,6 +374,8 @@ bool ReplyArea::sendExistingPhoto(
|
|||
} else if (showSlowmodeError()) {
|
||||
return false;
|
||||
}
|
||||
const auto action = prepareSendAction(options);
|
||||
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
copy.starsApproved = approved;
|
||||
|
@ -380,15 +383,13 @@ bool ReplyArea::sendExistingPhoto(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Api::SendExistingPhoto(
|
||||
Api::MessageToSend(prepareSendAction(options)),
|
||||
photo);
|
||||
Api::SendExistingPhoto(Api::MessageToSend(action), photo);
|
||||
|
||||
_controls->cancelReplyMessage();
|
||||
finishSending();
|
||||
|
@ -411,6 +412,9 @@ void ReplyArea::sendInlineResult(
|
|||
not_null<UserData*> bot,
|
||||
Api::SendOptions options,
|
||||
std::optional<MsgId> localMessageId) {
|
||||
auto action = prepareSendAction(options);
|
||||
action.generateLocal = true;
|
||||
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
copy.starsApproved = approved;
|
||||
|
@ -418,14 +422,12 @@ void ReplyArea::sendInlineResult(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = prepareSendAction(options);
|
||||
action.generateLocal = true;
|
||||
session().api().sendInlineResult(
|
||||
bot,
|
||||
result.get(),
|
||||
|
@ -677,6 +679,11 @@ void ReplyArea::sendingFilesConfirmed(
|
|||
void ReplyArea::sendingFilesConfirmed(
|
||||
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||
Api::SendOptions options) {
|
||||
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||
auto action = prepareSendAction(options);
|
||||
action.clearDraft = false;
|
||||
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
copy.starsApproved = approved;
|
||||
|
@ -684,16 +691,12 @@ void ReplyArea::sendingFilesConfirmed(
|
|||
};
|
||||
const auto checked = checkSendPayment(
|
||||
bundle->totalCount,
|
||||
options.starsApproved,
|
||||
action.options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||
auto action = prepareSendAction(options);
|
||||
action.clearDraft = false;
|
||||
if (bundle->sendComment) {
|
||||
auto message = Api::MessageToSend(action);
|
||||
message.textWithTags = base::take(bundle->caption);
|
||||
|
|
|
@ -96,7 +96,7 @@ private:
|
|||
|
||||
[[nodiscard]] bool checkSendPayment(
|
||||
int messagesCount,
|
||||
int starsApproved,
|
||||
Api::SendOptions options,
|
||||
Fn<void(int)> withPaymentApproved);
|
||||
|
||||
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
||||
|
|
|
@ -2396,6 +2396,10 @@ void SmallBalanceBox(
|
|||
return value.recipientId
|
||||
? owner->peer(value.recipientId)->shortName()
|
||||
: QString();
|
||||
}, [&](SmallBalanceForSuggest value) {
|
||||
return value.recipientId
|
||||
? owner->peer(value.recipientId)->shortName()
|
||||
: QString();
|
||||
});
|
||||
|
||||
auto needed = show->session().credits().balanceValue(
|
||||
|
@ -2442,6 +2446,11 @@ void SmallBalanceBox(
|
|||
lt_user,
|
||||
rpl::single(Ui::Text::Bold(name)),
|
||||
Ui::Text::RichLangValue))
|
||||
: v::is<SmallBalanceForSuggest>(source)
|
||||
? tr::lng_credits_small_balance_for_suggest(
|
||||
lt_channel,
|
||||
rpl::single(Ui::Text::Bold(name)),
|
||||
Ui::Text::RichLangValue)
|
||||
: name.isEmpty()
|
||||
? tr::lng_credits_small_balance_fallback(
|
||||
Ui::Text::RichLangValue)
|
||||
|
|
|
@ -233,13 +233,17 @@ struct SmallBalanceStarGift {
|
|||
struct SmallBalanceForMessage {
|
||||
PeerId recipientId;
|
||||
};
|
||||
struct SmallBalanceForSuggest {
|
||||
PeerId recipientId;
|
||||
};
|
||||
struct SmallBalanceSource : std::variant<
|
||||
SmallBalanceBot,
|
||||
SmallBalanceReaction,
|
||||
SmallBalanceSubscription,
|
||||
SmallBalanceDeepLink,
|
||||
SmallBalanceStarGift,
|
||||
SmallBalanceForMessage> {
|
||||
SmallBalanceForMessage,
|
||||
SmallBalanceForSuggest> {
|
||||
using variant::variant;
|
||||
};
|
||||
|
||||
|
|
|
@ -1370,3 +1370,11 @@ tonInput: InputField(defaultInputField) {
|
|||
starsFieldIconPosition: point(0px, 10px);
|
||||
tonFieldIconSize: 16px;
|
||||
tonFieldIconPosition: point(2px, 9px);
|
||||
|
||||
lowTonIconPadding: margins(12px, 20px, 12px, 0px);
|
||||
lowTonTitlePadding: margins(0px, 12px, 0px, 12px);
|
||||
lowTonTextPadding: margins(0px, 0px, 0px, 8px);
|
||||
lowTonText: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 100px;
|
||||
align: align(top);
|
||||
}
|
||||
|
|
|
@ -1798,6 +1798,10 @@ void PeerMenuShareContactBox(
|
|||
state->share = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = Api::SendAction(strong, options);
|
||||
action.clearDraft = false;
|
||||
|
||||
const auto withPaymentApproved = [=](int stars) {
|
||||
if (const auto onstack = state->share) {
|
||||
auto copy = options;
|
||||
|
@ -1808,8 +1812,8 @@ void PeerMenuShareContactBox(
|
|||
const auto checked = state->sendPayment.check(
|
||||
navigation,
|
||||
peer,
|
||||
action.options,
|
||||
1,
|
||||
options.starsApproved,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
|
@ -1818,8 +1822,6 @@ void PeerMenuShareContactBox(
|
|||
strong,
|
||||
ShowAtTheEndMsgId,
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
auto action = Api::SendAction(strong, options);
|
||||
action.clearDraft = false;
|
||||
strong->session().api().shareContact(user, action);
|
||||
state->share = nullptr;
|
||||
};
|
||||
|
@ -1887,6 +1889,12 @@ void PeerMenuCreatePoll(
|
|||
const auto weak = QPointer<CreatePollBox>(box);
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->create = [=](const CreatePollBox::Result &result) {
|
||||
auto action = Api::SendAction(
|
||||
peer->owner().history(peer),
|
||||
result.options);
|
||||
action.replyTo = replyTo;
|
||||
action.options.suggest = suggest;
|
||||
|
||||
const auto withPaymentApproved = crl::guard(weak, [=](int stars) {
|
||||
if (const auto onstack = state->create) {
|
||||
auto copy = result;
|
||||
|
@ -1897,17 +1905,13 @@ void PeerMenuCreatePoll(
|
|||
const auto checked = state->sendPayment.check(
|
||||
controller,
|
||||
peer,
|
||||
action.options,
|
||||
1,
|
||||
result.options.starsApproved,
|
||||
withPaymentApproved);
|
||||
if (!checked || std::exchange(state->lock, true)) {
|
||||
return;
|
||||
}
|
||||
auto action = Api::SendAction(
|
||||
peer->owner().history(peer),
|
||||
result.options);
|
||||
action.replyTo = replyTo;
|
||||
action.options.suggest = suggest;
|
||||
|
||||
const auto local = action.history->localDraft(
|
||||
replyTo.topicRootId,
|
||||
replyTo.monoforumPeerId);
|
||||
|
@ -2002,20 +2006,22 @@ void PeerMenuCreateTodoList(
|
|||
onstack(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(
|
||||
peer->owner().history(peer),
|
||||
result.options);
|
||||
action.replyTo = replyTo;
|
||||
action.options.suggest = suggest;
|
||||
|
||||
const auto checked = state->sendPayment.check(
|
||||
controller,
|
||||
peer,
|
||||
action.options,
|
||||
1,
|
||||
withPaymentApproved);
|
||||
if (!checked || std::exchange(state->lock, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto local = action.history->localDraft(
|
||||
replyTo.topicRootId,
|
||||
replyTo.monoforumPeerId);
|
||||
|
|
Loading…
Add table
Reference in a new issue