Improve bidding logic.

This commit is contained in:
John Preston
2025-11-13 14:48:23 +04:00
parent cab93600dd
commit 9b599644d9
5 changed files with 53 additions and 40 deletions
+1
View File
@@ -4038,6 +4038,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_auction_bid_your_winning" = "You're winning";
"lng_auction_bid_winners_title" = "Top 3 Winners";
"lng_auction_bid_place" = "Place a {stars} Bid";
"lng_auction_bid_increase" = "Add {stars} to Your Bid";
"lng_auction_bid_placed_title" = "Your bid has been placed";
"lng_auction_bid_increased_title" = "Your bid has been increased";
"lng_auction_bid_done_text#one" = "If you fall below the **top {count}**, your bid will roll over to the next round.";
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/star_gift_auction_box.h"
#include "base/unixtime.h"
#include "boxes/send_credits_box.h" // CreditsEmojiSmall
#include "boxes/star_gift_box.h"
#include "calls/group/calls_group_common.h"
#include "core/credits_amount.h"
@@ -47,6 +48,7 @@ namespace {
constexpr auto kAuctionAboutShownPref = "gift_auction_about_shown"_cs;
constexpr auto kBidPlacedToastDuration = 5 * crl::time(1000);
constexpr auto kMaxShownBid = 30'000;
[[nodiscard]] rpl::producer<int> MinutesLeftTillValue(TimeId endDate) {
return [=](auto consumer) {
@@ -128,9 +130,24 @@ void AuctionBidBox(not_null<GenericBox*> box, AuctionBidBoxArgs &&args) {
rpl::variable<Data::GiftAuctionState>
>(std::move(args.state));
auto submit = [=](rpl::producer<int> amount) {
return std::move(amount) | rpl::map([=](int count) {
return TextWithEntities{ "Place a " + QString::number(count) + " Bid" };
});
return rpl::combine(
state->value(),
std::move(amount)
) | rpl::map([=](const Data::GiftAuctionState &state, int count) {
return !state.my.bid
? tr::lng_auction_bid_place(
lt_stars,
rpl::single(Ui::CreditsEmojiSmall().append(
Lang::FormatCountDecimal(count))),
tr::marked)
: (count <= state.my.bid)
? tr::lng_box_ok(tr::marked)
: tr::lng_auction_bid_increase(
lt_stars,
rpl::single(Ui::CreditsEmojiSmall().append(
Lang::FormatCountDecimal(count - state.my.bid))),
tr::marked);
}) | rpl::flatten_latest();
};
const auto show = args.show;
const auto session = &show->session();
@@ -165,15 +182,16 @@ void AuctionBidBox(not_null<GenericBox*> box, AuctionBidBoxArgs &&args) {
};
PlaceAuctionBid(show, peer, amount, now, done);
};
const auto mine = state->current().my.bid;
PaidReactionsBox(box, {
.min = int(state->current().my.bid
.min = int(mine
? state->current().my.minBidAmount
: state->current().minBidAmount),
.explicitlyAllowed = int(mine),
.chosen = int(state->current().my.bid),
.max = 10'000,
.max = kMaxShownBid,
.top = std::move(top),
.session = session,
.name = u"hello"_q,
.submit = submit,
.colorings = session->appConfig().groupCallColorings(),
.balanceValue = session->credits().balanceValue(),
@@ -92,11 +92,16 @@ struct Discreter {
thresholds.emplace(1. / 8, 10);
thresholds.emplace(1. / 3, 100);
thresholds.emplace(1., max);
} else {
} else if (max <= 10000) {
thresholds.emplace(1. / 8, 10);
thresholds.emplace(1. / 3, 100);
thresholds.emplace(2. / 3, 1000);
thresholds.emplace(1., max);
} else {
thresholds.emplace(1. / 10, 10);
thresholds.emplace(1. / 6, 100);
thresholds.emplace(1. / 3, 1000);
thresholds.emplace(1., max);
}
const auto ratioToValue = [=](float64 ratio) {
@@ -131,12 +136,17 @@ void PaidReactionSlider(
not_null<VerticalLayout*> container,
const style::MediaSlider &st,
int min,
int explicitlyAllowed,
int current,
int max,
Fn<void(int)> changed,
Fn<QColor(int)> activeFgOverride = nullptr) {
Expects(current >= 1 && current <= max);
Expects(explicitlyAllowed <= max);
if (!explicitlyAllowed) {
explicitlyAllowed = min;
}
const auto slider = container->add(
object_ptr<MediaSlider>(container, st),
st::boxRowPadding + QMargins(0, st::paidReactSliderTop, 0, 0));
@@ -161,7 +171,9 @@ void PaidReactionSlider(
slider->setValue(discreter.valueToRatio(current));
const auto ratioToValue = [=](float64 ratio) {
const auto value = discreter.ratioToValue(ratio);
return std::max(value, min);
return (value <= explicitlyAllowed && explicitlyAllowed < min)
? explicitlyAllowed
: std::max(value, min);
};
slider->setAdjustCallback([=](float64 ratio) {
return discreter.valueToRatio(ratioToValue(ratio));
@@ -569,8 +581,17 @@ void PaidReactionsBox(
const auto dark = args.dark;
args.min = std::max(args.min, 1);
args.max = std::max(args.max, args.min + 1);
args.chosen = std::clamp(args.chosen, args.min, args.max);
args.max = std::max({
args.min + 1,
args.max,
args.explicitlyAllowed,
args.chosen,
});
const auto allowed = args.explicitlyAllowed;
args.chosen = (allowed && args.chosen == allowed)
? allowed
: std::clamp(args.chosen, args.min, args.max);
box->setWidth(st::boxWideWidth);
box->setStyle(dark ? st::darkEditStarsBox : st::paidReactBox);
@@ -651,6 +672,7 @@ void PaidReactionsBox(
content,
(dark ? st::darkEditStarsSlider : st::paidReactSlider),
args.min,
args.explicitlyAllowed,
args.chosen,
args.max,
changed,
@@ -778,35 +800,7 @@ void PaidReactionsBox(
args.send(0, state->shownPeer.current());
}, box->lifetime());
{
const auto buttonLabel = CreateChild<FlatLabel>(
button,
rpl::single(QString()),
st::creditsBoxButtonLabel);
args.submit(
state->chosen.value()
) | rpl::start_with_next([=](const TextWithEntities &text) {
buttonLabel->setMarkedText(text);
}, buttonLabel->lifetime());
buttonLabel->setTextColorOverride(
box->getDelegate()->style().button.textFg->c);
button->sizeValue(
) | rpl::start_with_next([=](const QSize &size) {
buttonLabel->moveToLeft(
(size.width() - buttonLabel->width()) / 2,
(size.height() - buttonLabel->height()) / 2);
}, buttonLabel->lifetime());
buttonLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
}
box->widthValue(
) | rpl::start_with_next([=](int width) {
const auto &padding = st::paidReactBox.buttonPadding;
button->resizeToWidth(width
- padding.left()
- padding.right());
button->moveToLeft(padding.left(), button->y());
}, button->lifetime());
button->setText(args.submit(state->chosen.value()));
{
const auto balance = Settings::AddBalanceWidget(
@@ -35,6 +35,7 @@ struct PaidReactionTop {
struct PaidReactionBoxArgs {
int min = 0;
int explicitlyAllowed = 0;
int chosen = 0;
int max = 0;
@@ -404,7 +404,6 @@ boostFeatureProfileIcon: icon{{ "settings/premium/features/feature_profile_cover
paidReactBox: Box(boostBox) {
buttonPadding: margins(22px, 22px, 22px, 22px);
buttonHeight: 42px;
button: RoundButton(defaultActiveButton) {
height: 42px;
textTop: 12px;