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