Use paid messages values from appConfig.

This commit is contained in:
John Preston 2025-03-01 09:22:07 +04:00
parent 9032489786
commit 827040f487
7 changed files with 142 additions and 102 deletions

View file

@ -45,9 +45,7 @@ namespace {
constexpr auto kPremiumsRowId = PeerId(FakeChatId(BareId(1))).value; constexpr auto kPremiumsRowId = PeerId(FakeChatId(BareId(1))).value;
constexpr auto kMiniAppsRowId = PeerId(FakeChatId(BareId(2))).value; constexpr auto kMiniAppsRowId = PeerId(FakeChatId(BareId(2))).value;
constexpr auto kGetPercent = 85;
constexpr auto kStarsMin = 1; constexpr auto kStarsMin = 1;
constexpr auto kStarsMax = 10000;
constexpr auto kDefaultChargeStars = 10; constexpr auto kDefaultChargeStars = 10;
using Exceptions = Api::UserPrivacy::Exceptions; using Exceptions = Api::UserPrivacy::Exceptions;
@ -466,6 +464,7 @@ auto PrivacyExceptionsBoxController::createRow(not_null<History*> history)
int valuesCount, int valuesCount,
Fn<int(int)> valueByIndex, Fn<int(int)> valueByIndex,
int value, int value,
int maxValue,
Fn<void(int)> valueProgress, Fn<void(int)> valueProgress,
Fn<void(int)> valueFinished) { Fn<void(int)> valueFinished) {
auto result = object_ptr<Ui::VerticalLayout>(parent); auto result = object_ptr<Ui::VerticalLayout>(parent);
@ -478,7 +477,7 @@ auto PrivacyExceptionsBoxController::createRow(not_null<History*> history)
*labelStyle); *labelStyle);
const auto max = Ui::CreateChild<Ui::FlatLabel>( const auto max = Ui::CreateChild<Ui::FlatLabel>(
raw, raw,
QString::number(kStarsMax), QString::number(maxValue),
*labelStyle); *labelStyle);
const auto current = Ui::CreateChild<Ui::FlatLabel>( const auto current = Ui::CreateChild<Ui::FlatLabel>(
raw, raw,
@ -999,28 +998,22 @@ void EditMessagesPrivacyBox(
Ui::AddDividerText(inner, tr::lng_messages_privacy_about()); Ui::AddDividerText(inner, tr::lng_messages_privacy_about());
const auto charged = inner->add( const auto available = session->appConfig().paidMessagesAvailable();
object_ptr<Ui::Radiobutton>(
inner,
group,
kOptionCharge,
tr::lng_messages_privacy_charge(tr::now),
st::messagePrivacyCheck),
st::settingsSendTypePadding + style::margins(
0,
st::messagePrivacyBottomSkip,
0,
st::messagePrivacyBottomSkip));
Ui::AddDividerText(inner, tr::lng_messages_privacy_charge_about()); const auto charged = available
? inner->add(
const auto chargeWrap = inner->add( object_ptr<Ui::Radiobutton>(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( inner,
inner, group,
object_ptr<Ui::VerticalLayout>(inner))); kOptionCharge,
const auto chargeInner = chargeWrap->entity(); tr::lng_messages_privacy_charge(tr::now),
st::messagePrivacyCheck),
Ui::AddSkip(chargeInner); st::settingsSendTypePadding + style::margins(
0,
st::messagePrivacyBottomSkip,
0,
st::messagePrivacyBottomSkip))
: nullptr;
struct State { struct State {
rpl::variable<int> stars; rpl::variable<int> stars;
@ -1028,54 +1021,67 @@ void EditMessagesPrivacyBox(
const auto state = std::make_shared<State>(); const auto state = std::make_shared<State>();
const auto savedValue = privacy->newChargeStarsCurrent(); const auto savedValue = privacy->newChargeStarsCurrent();
state->stars = SetupChargeSlider( if (available) {
chargeInner, Ui::AddDividerText(inner, tr::lng_messages_privacy_charge_about());
session->user(),
savedValue);
Ui::AddSkip(chargeInner); const auto chargeWrap = inner->add(
Ui::AddSubsectionTitle( object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
chargeInner, inner,
tr::lng_messages_privacy_exceptions()); object_ptr<Ui::VerticalLayout>(inner)));
const auto chargeInner = chargeWrap->entity();
const auto key = Api::UserPrivacy::Key::NoPaidMessages; Ui::AddSkip(chargeInner);
session->api().userPrivacy().reload(key);
auto label = session->api().userPrivacy().value(
key
) | rpl::map([=](const Api::UserPrivacy::Rule &value) {
using namespace Settings;
const auto always = ExceptionUsersCount(value.always.peers);
return always
? tr::lng_edit_privacy_exceptions_count(
tr::now,
lt_count,
always)
: QString();
});
const auto exceptions = Settings::AddButtonWithLabel( state->stars = SetupChargeSlider(
chargeInner, chargeInner,
tr::lng_messages_privacy_remove_fee(), session->user(),
std::move(label), savedValue);
st::settingsButtonNoIcon);
const auto shower = exceptions->lifetime().make_state<rpl::lifetime>(); Ui::AddSkip(chargeInner);
exceptions->setClickedCallback([=] { Ui::AddSubsectionTitle(
*shower = session->api().userPrivacy().value( chargeInner,
tr::lng_messages_privacy_exceptions());
const auto key = Api::UserPrivacy::Key::NoPaidMessages;
session->api().userPrivacy().reload(key);
auto label = session->api().userPrivacy().value(
key key
) | rpl::take( ) | rpl::map([=](const Api::UserPrivacy::Rule &value) {
1 using namespace Settings;
) | rpl::start_with_next([=](const Api::UserPrivacy::Rule &value) { const auto always = ExceptionUsersCount(value.always.peers);
EditNoPaidMessagesExceptions(controller, value); return always
? tr::lng_edit_privacy_exceptions_count(
tr::now,
lt_count,
always)
: QString();
}); });
});
Ui::AddSkip(chargeInner);
Ui::AddDividerText(chargeInner, tr::lng_messages_privacy_remove_about());
using namespace rpl::mappers; const auto exceptions = Settings::AddButtonWithLabel(
chargeWrap->toggleOn(group->value() | rpl::map(_1 == kOptionCharge)); chargeInner,
chargeWrap->finishAnimating(); tr::lng_messages_privacy_remove_fee(),
std::move(label),
st::settingsButtonNoIcon);
const auto shower = exceptions->lifetime().make_state<rpl::lifetime>();
exceptions->setClickedCallback([=] {
*shower = session->api().userPrivacy().value(
key
) | rpl::take(
1
) | rpl::start_with_next([=](const Api::UserPrivacy::Rule &value) {
EditNoPaidMessagesExceptions(controller, value);
});
});
Ui::AddSkip(chargeInner);
Ui::AddDividerText(
chargeInner,
tr::lng_messages_privacy_remove_about());
using namespace rpl::mappers;
chargeWrap->toggleOn(group->value() | rpl::map(_1 == kOptionCharge));
chargeWrap->finishAnimating();
}
using WeakToast = base::weak_ptr<Ui::Toast::Instance>; using WeakToast = base::weak_ptr<Ui::Toast::Instance>;
const auto toast = std::make_shared<WeakToast>(); const auto toast = std::make_shared<WeakToast>();
const auto showToast = [=] { const auto showToast = [=] {
@ -1108,7 +1114,9 @@ void EditMessagesPrivacyBox(
if (!allowed()) { if (!allowed()) {
CreateRadiobuttonLock(restricted, st::messagePrivacyCheck); CreateRadiobuttonLock(restricted, st::messagePrivacyCheck);
CreateRadiobuttonLock(charged, st::messagePrivacyCheck); if (charged) {
CreateRadiobuttonLock(charged, st::messagePrivacyCheck);
}
group->setChangedCallback([=](int value) { group->setChangedCallback([=](int value) {
if (value == kOptionPremium || value == kOptionCharge) { if (value == kOptionPremium || value == kOptionCharge) {
@ -1170,19 +1178,20 @@ rpl::producer<int> SetupChargeSlider(
: tr::lng_messages_privacy_price()); : tr::lng_messages_privacy_price());
auto values = std::vector<int>(); auto values = std::vector<int>();
const auto maxStars = peer->session().appConfig().paidMessageStarsMax();
if (chargeStars < kStarsMin) { if (chargeStars < kStarsMin) {
values.push_back(chargeStars); values.push_back(chargeStars);
} }
for (auto i = kStarsMin; i < 100; ++i) { for (auto i = kStarsMin; i < std::min(100, maxStars); ++i) {
values.push_back(i); values.push_back(i);
} }
for (auto i = 100; i < 1000; i += 10) { for (auto i = 100; i < std::min(1000, maxStars); i += 10) {
if (i < chargeStars + 10 && chargeStars < i) { if (i < chargeStars + 10 && chargeStars < i) {
values.push_back(chargeStars); values.push_back(chargeStars);
} }
values.push_back(i); values.push_back(i);
} }
for (auto i = 1000; i < kStarsMax + 1; i += 100) { for (auto i = 1000; i < maxStars + 1; i += 100) {
if (i < chargeStars + 100 && chargeStars < i) { if (i < chargeStars + 100 && chargeStars < i) {
values.push_back(chargeStars); values.push_back(chargeStars);
} }
@ -1200,6 +1209,7 @@ rpl::producer<int> SetupChargeSlider(
valuesCount, valuesCount,
[=](int index) { return values[index]; }, [=](int index) { return values[index]; },
chargeStars, chargeStars,
maxStars,
setStars, setStars,
setStars), setStars),
st::boxRowPadding); st::boxRowPadding);
@ -1208,19 +1218,18 @@ rpl::producer<int> SetupChargeSlider(
Ui::AddSkip(container, skip); Ui::AddSkip(container, skip);
auto dollars = state->stars.value() | rpl::map([=](int stars) { auto dollars = state->stars.value() | rpl::map([=](int stars) {
const auto ratio = peer->session().appConfig().get<float64>( const auto ratio = peer->session().appConfig().starsWithdrawRate();
u"stars_usd_withdraw_rate_x1000"_q, const auto dollars = int(base::SafeRound(stars * ratio));
1200);
const auto dollars = int(base::SafeRound(stars * (ratio / 1000.)));
return '~' + Ui::FillAmountAndCurrency(dollars, u"USD"_q); return '~' + Ui::FillAmountAndCurrency(dollars, u"USD"_q);
}); });
const auto percent = peer->session().appConfig().paidMessageCommission();
Ui::AddDividerText( Ui::AddDividerText(
container, container,
(group (group
? tr::lng_rights_charge_price_about ? tr::lng_rights_charge_price_about
: tr::lng_messages_privacy_price_about)( : tr::lng_messages_privacy_price_about)(
lt_percent, lt_percent,
rpl::single(QString::number(kGetPercent) + '%'), rpl::single(QString::number(percent / 10.) + '%'),
lt_amount, lt_amount,
std::move(dollars))); std::move(dollars)));

View file

@ -1160,34 +1160,39 @@ void ShowEditPeerPermissionsBox(
rpl::variable<int> starsPerMessage; rpl::variable<int> starsPerMessage;
}; };
const auto state = inner->lifetime().make_state<State>(); const auto state = inner->lifetime().make_state<State>();
const auto channel = peer->asChannel();
const auto available = channel && channel->paidMessagesAvailable();
Ui::AddSkip(inner); Ui::AddSkip(inner);
Ui::AddDivider(inner); Ui::AddDivider(inner);
Ui::AddSkip(inner); auto charging = (Ui::SettingsButton*)nullptr;
const auto starsPerMessage = peer->isChannel() if (available) {
? peer->asChannel()->starsPerMessage() Ui::AddSkip(inner);
: 0; const auto starsPerMessage = peer->isChannel()
const auto charging = inner->add(object_ptr<Ui::SettingsButton>( ? peer->asChannel()->starsPerMessage()
inner, : 0;
tr::lng_rights_charge_stars(), charging = inner->add(object_ptr<Ui::SettingsButton>(
st::settingsButtonNoIcon));
charging->toggleOn(rpl::single(starsPerMessage > 0));
Ui::AddSkip(inner);
Ui::AddDividerText(inner, tr::lng_rights_charge_stars_about());
const auto chargeWrap = inner->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
inner, inner,
object_ptr<Ui::VerticalLayout>(inner))); tr::lng_rights_charge_stars(),
chargeWrap->toggleOn(charging->toggledValue()); st::settingsButtonNoIcon));
chargeWrap->finishAnimating(); charging->toggleOn(rpl::single(starsPerMessage > 0));
const auto chargeInner = chargeWrap->entity(); Ui::AddSkip(inner);
Ui::AddDividerText(inner, tr::lng_rights_charge_stars_about());
Ui::AddSkip(chargeInner); const auto chargeWrap = inner->add(
state->starsPerMessage = SetupChargeSlider( object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
chargeInner, inner,
peer, object_ptr<Ui::VerticalLayout>(inner)));
starsPerMessage); chargeWrap->toggleOn(charging->toggledValue());
chargeWrap->finishAnimating();
const auto chargeInner = chargeWrap->entity();
Ui::AddSkip(chargeInner);
state->starsPerMessage = SetupChargeSlider(
chargeInner,
peer,
starsPerMessage);
}
static constexpr auto kSendRestrictions = Flag::EmbedLinks static constexpr auto kSendRestrictions = Flag::EmbedLinks
| Flag::SendGames | Flag::SendGames
@ -1242,7 +1247,7 @@ void ShowEditPeerPermissionsBox(
const auto boostsUnrestrict = hasRestrictions const auto boostsUnrestrict = hasRestrictions
? state->boostsUnrestrict.current() ? state->boostsUnrestrict.current()
: 0; : 0;
const auto starsPerMessage = charging->toggled() const auto starsPerMessage = (charging && charging->toggled())
? state->starsPerMessage.current() ? state->starsPerMessage.current()
: 0; : 0;
done({ done({

View file

@ -37,10 +37,7 @@ void Credits::apply(const MTPDupdateStarsBalance &data) {
rpl::producer<float64> Credits::rateValue( rpl::producer<float64> Credits::rateValue(
not_null<PeerData*> ownedBotOrChannel) { not_null<PeerData*> ownedBotOrChannel) {
return rpl::single( return rpl::single(_session->appConfig().starsWithdrawRate());
_session->appConfig().get<float64>(
u"stars_usd_withdraw_rate_x1000"_q,
1200) / 1000.);
} }
void Credits::load(bool force) { void Credits::load(bool force) {

View file

@ -1167,7 +1167,8 @@ void ApplyChannelUpdate(
| Flag::CanViewRevenue | Flag::CanViewRevenue
| Flag::PaidMediaAllowed | Flag::PaidMediaAllowed
| Flag::CanViewCreditsRevenue | Flag::CanViewCreditsRevenue
| Flag::StargiftsAvailable; | Flag::StargiftsAvailable
| Flag::PaidMessagesAvailable;
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()
@ -1191,6 +1192,9 @@ void ApplyChannelUpdate(
: Flag()) : Flag())
| (update.is_stargifts_available() | (update.is_stargifts_available()
? Flag::StargiftsAvailable ? Flag::StargiftsAvailable
: Flag())
| (update.is_paid_messages_available()
? Flag::PaidMessagesAvailable
: Flag())); : Flag()));
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()) {

View file

@ -72,6 +72,7 @@ enum class ChannelDataFlag : uint64 {
CanViewCreditsRevenue = (1ULL << 34), CanViewCreditsRevenue = (1ULL << 34),
SignatureProfiles = (1ULL << 35), SignatureProfiles = (1ULL << 35),
StargiftsAvailable = (1ULL << 36), StargiftsAvailable = (1ULL << 36),
PaidMessagesAvailable = (1ULL << 37),
}; };
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>;
@ -262,6 +263,9 @@ public:
[[nodiscard]] bool stargiftsAvailable() const { [[nodiscard]] bool stargiftsAvailable() const {
return flags() & Flag::StargiftsAvailable; return flags() & Flag::StargiftsAvailable;
} }
[[nodiscard]] bool paidMessagesAvailable() const {
return flags() & Flag::PaidMessagesAvailable;
}
[[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights( [[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights(
not_null<PeerData*> participant); not_null<PeerData*> participant);

View file

@ -73,6 +73,22 @@ int AppConfig::starrefCommissionMax() const {
return get<int>(u"starref_max_commission_permille"_q, 900); return get<int>(u"starref_max_commission_permille"_q, 900);
} }
float64 AppConfig::starsWithdrawRate() const {
return get<float64>(u"stars_usd_withdraw_rate_x1000"_q, 1300) / 1000.;
}
bool AppConfig::paidMessagesAvailable() const {
return get<bool>(u"stars_paid_messages_available"_q, false);
}
int AppConfig::paidMessageStarsMax() const {
return get<int>(u"stars_paid_message_amount_max"_q, 10'000);
}
int AppConfig::paidMessageCommission() const {
return get<int>(u"stars_paid_message_commission_permille"_q, 850);
}
void AppConfig::refresh(bool force) { void AppConfig::refresh(bool force) {
if (_requestId || !_api) { if (_requestId || !_api) {
if (force) { if (force) {

View file

@ -72,6 +72,11 @@ public:
[[nodiscard]] int starrefCommissionMin() const; [[nodiscard]] int starrefCommissionMin() const;
[[nodiscard]] int starrefCommissionMax() const; [[nodiscard]] int starrefCommissionMax() const;
[[nodiscard]] float64 starsWithdrawRate() const;
[[nodiscard]] bool paidMessagesAvailable() const;
[[nodiscard]] int paidMessageStarsMax() const;
[[nodiscard]] int paidMessageCommission() const;
void refresh(bool force = false); void refresh(bool force = false);
private: private: