Add balance of stars / TON.

This commit is contained in:
John Preston 2025-06-27 20:25:58 +04:00
parent 12b9b3ce71
commit 915a1b105c
14 changed files with 122 additions and 47 deletions

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icon / Filled / checklist</title>
<g id="Icon-/-Filled-/-checklist" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M12,4 C16.416,4 20,7.584 20,12 C20,16.416 16.416,20 12,20 C7.584,20 4,16.416 4,12 C4,7.584 7.584,4 12,4 Z M16.4818432,9.54348643 C16.1872637,9.22288416 15.7053635,9.21829494 15.4054889,9.53323613 L10.7733532,14.3979954 L8.99451107,12.5296222 C8.69463652,12.2146811 8.21273632,12.2192703 7.91815685,12.5398725 C7.62357737,12.8604748 7.62786989,13.3756846 7.92774444,13.6906258 L10.1546212,16.0293878 C10.4981762,16.3902041 11.0487833,16.3902041 11.3923383,16.0293878 L16.4722556,10.6942397 C16.7721301,10.3792985 16.7764226,9.8640887 16.4818432,9.54348643 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 975 B

View file

@ -4497,8 +4497,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_suggest_warn_text_ton" = "You won't receive **TON** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published.";
"lng_suggest_warn_delete_anyway" = "Delete Anyway";
"lng_suggest_low_ton_title" = "{amount} TON Needed";
"lng_suggest_low_ton_text" = "Buy **TON** to suggest message to {channel} and others.";
"lng_suggest_low_ton_fragment" = "Buy on Fragment";
"lng_suggest_low_ton_text" = "You can add funds to your balance via the third-party platform Fragment.";
"lng_suggest_low_ton_fragment" = "Add Funds via Fragment";
"lng_suggest_low_ton_fragment_url" = "https://fragment.com/ads/topup";
"lng_reply_in_another_title" = "Reply in...";

View file

@ -256,6 +256,7 @@ void ConfirmSubscriptionBox(
{
const auto balance = Settings::AddBalanceWidget(
content,
session,
session->credits().balanceValue(),
true);
session->credits().load(true);

View file

@ -487,6 +487,7 @@ void SendCreditsBox(
session->credits().load(true);
const auto balance = Settings::AddBalanceWidget(
content,
session,
session->credits().balanceValue(),
false);
rpl::combine(

View file

@ -122,13 +122,21 @@ void ChooseSuggestPriceBox(
const auto starsMax = session->appConfig().suggestedPostStarsMax();
const auto nanoTonMin = session->appConfig().suggestedPostNanoTonMin();
const auto nanoTonMax = session->appConfig().suggestedPostNanoTonMax();
const auto container = box->verticalLayout();
box->setStyle(st::suggestPriceBox);
box->setTitle((args.mode == SuggestMode::New)
? tr::lng_suggest_options_title()
: tr::lng_suggest_options_change());
box->setNoContentMargin(true);
Ui::AddSkip(container, st::boxTitleHeight * 1.1);
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
object_ptr<Ui::FlatLabel>(
box,
((args.mode == SuggestMode::New)
? tr::lng_suggest_options_title()
: tr::lng_suggest_options_change()),
st::settingsPremiumUserTitle)));
const auto container = box->verticalLayout();
state->buttons.push_back({
.text = Ui::Text::String(
st::semiboldTextStyle,
@ -159,7 +167,7 @@ void ChooseSuggestPriceBox(
const auto buttons = box->addRow(
object_ptr<Ui::RpWidget>(box),
(st::boxRowPadding
- QMargins(padding.left() / 2, 0, padding.right() / 2, 0)));
- QMargins(padding.left() / 2, -st::normalFont->height, padding.right() / 2, 0)));
const auto height = y
+ state->buttons.back().geometry.height()
+ st::giftBoxTabsMargin.bottom();
@ -253,7 +261,7 @@ void ChooseSuggestPriceBox(
Ui::AddSubsectionTitle(
starsInner,
tr::lng_suggest_options_stars_price(),
QMargins(added.left(), 0, added.right(), 0));
QMargins(added.left(), 0, added.right(), -st::defaultSubsectionTitlePadding.bottom()));
const auto starsFieldWrap = starsInner->add(
object_ptr<Ui::FixedHeightWidget>(
@ -295,7 +303,7 @@ void ChooseSuggestPriceBox(
Ui::AddSubsectionTitle(
tonInner,
tr::lng_suggest_options_ton_price(),
QMargins(added.left(), 0, added.right(), 0));
QMargins(added.left(), 0, added.right(), -st::defaultSubsectionTitlePadding.bottom()));
const auto tonFieldWrap = tonInner->add(
object_ptr<Ui::FixedHeightWidget>(
@ -522,6 +530,39 @@ void ChooseSuggestPriceBox(
}) | rpl::start_with_next([=] {
button->resizeToWidth(buttonWidth);
}, button->lifetime());
{
const auto close = Ui::CreateChild<Ui::IconButton>(
container,
st::boxTitleClose);
close->setClickedCallback([=] { box->closeBox(); });
container->widthValue() | rpl::start_with_next([=](int) {
close->moveToRight(0, 0);
}, close->lifetime());
}
{
session->credits().load(true);
session->credits().tonLoad(true);
const auto balance = Settings::AddBalanceWidget(
container,
session,
rpl::conditional(
state->ton.value(),
session->credits().tonBalanceValue(),
session->credits().balanceValue()),
false);
rpl::combine(
balance->sizeValue(),
container->sizeValue()
) | rpl::start_with_next([=](const QSize &, const QSize &) {
balance->moveToLeft(
st::creditsHistoryRightSkip * 2,
st::creditsHistoryRightSkip);
balance->update();
}, balance->lifetime());
}
}
bool CanEditSuggestedMessage(not_null<HistoryItem*> item) {
@ -546,6 +587,11 @@ void InsufficientTonBox(
not_null<Ui::GenericBox*> box,
not_null<PeerData*> peer,
CreditsAmount required) {
box->setStyle(st::suggestPriceBox);
box->addTopButton(st::boxTitleClose, [=] {
box->closeBox();
});
auto icon = Settings::CreateLottieIcon(
box->verticalLayout(),
{
@ -571,21 +617,24 @@ void InsufficientTonBox(
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),
tr::lng_suggest_low_ton_text(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();
});
const auto url = tr::lng_suggest_low_ton_fragment_url(tr::now);
const auto button = box->addButton(
tr::lng_suggest_low_ton_fragment(),
[=] { UrlClickHandler::Open(url); });
const auto buttonWidth = st::boxWidth
- rect::m::sum::h(st::suggestPriceBox.buttonPadding);
button->widthValue() | rpl::filter([=] {
return (button->widthNoMargins() != buttonWidth);
}) | rpl::start_with_next([=] {
button->resizeToWidth(buttonWidth);
}, button->lifetime());
}
SuggestOptions::SuggestOptions(

View file

@ -251,6 +251,7 @@ void ShowPaidReactionDetails(
.chosen = chosen,
.max = max,
.top = std::move(top),
.session = &channel->session(),
.channel = channel->name(),
.submit = std::move(submitText),
.balanceValue = session->credits().balanceValue(),

View file

@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Settings {
[[nodiscard]] not_null<Ui::RpWidget*> AddBalanceWidget(
not_null<Ui::RpWidget*> parent,
not_null<Main::Session*> session,
rpl::producer<CreditsAmount> balanceValue,
bool rightAlign,
rpl::producer<float64> opacityValue = nullptr);
@ -572,6 +573,7 @@ void PaidReactionsBox(
{
const auto balance = Settings::AddBalanceWidget(
content,
args.session,
std::move(args.balanceValue),
false);
rpl::combine(

View file

@ -13,6 +13,10 @@ namespace style {
struct RoundCheckbox;
} // namespace style
namespace Main {
class Session;
} // namespace Main
namespace Ui {
class BoxContent;
@ -39,6 +43,7 @@ struct PaidReactionBoxArgs {
std::vector<PaidReactionTop> top;
not_null<Main::Session*> session;
QString channel;
Fn<rpl::producer<TextWithContext>(rpl::producer<int> amount)> submit;
rpl::producer<CreditsAmount> balanceValue;

View file

@ -103,6 +103,7 @@ settingsPremiumIconLastSeen: icon {{ "settings/premium/lastseen", settingsIconFg
settingsPremiumIconPrivacy: icon {{ "settings/premium/privacy", settingsIconFg }};
settingsPremiumIconBusiness: icon {{ "settings/premium/market", settingsIconFg }};
settingsPremiumIconEffects: icon {{ "settings/premium/effects", settingsIconFg }};
settingsPremiumIconChecklist: icon {{ "settings/premium/checklist", settingsIconFg }};
settingsStoriesIconOrder: icon {{ "settings/premium/stories_order", premiumButtonBg1 }};
settingsStoriesIconStealth: icon {{ "menu/stealth", premiumButtonBg1 }};

View file

@ -607,6 +607,7 @@ QPointer<Ui::RpWidget> Credits::createPinnedToTop(
{
const auto balance = AddBalanceWidget(
content,
&_controller->session(),
_controller->session().credits().balanceValue(),
true,
content->heightValue() | rpl::map([=](int height) {

View file

@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/bot/starref/info_bot_starref_common.h"
#include "info/channel_statistics/boosts/giveaway/boost_badge.h" // InfiniteRadialAnimationWidget.
#include "info/channel_statistics/earn/info_channel_earn_widget.h" // Info::ChannelEarn::Make.
#include "info/channel_statistics/earn/earn_icons.h"
#include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
#include "info/statistics/info_statistics_list_controllers.h"
@ -684,19 +685,17 @@ void FillCreditOptions(
not_null<Ui::RpWidget*> AddBalanceWidget(
not_null<Ui::RpWidget*> parent,
not_null<Main::Session*> session,
rpl::producer<CreditsAmount> balanceValue,
bool rightAlign,
rpl::producer<float64> opacityValue) {
struct State final {
QImage star;
float64 opacity = 1.0;
Ui::Text::String label;
Ui::Text::String count;
};
const auto balance = Ui::CreateChild<Balance>(parent);
const auto state = balance->lifetime().make_state<State>();
state->star = QImage(Ui::GenerateStars(st::creditsBalanceStarHeight, 1));
const auto starSize = state->star.size() / style::DevicePixelRatio();
state->label = Ui::Text::String(
st::defaultTextStyle,
tr::lng_credits_summary_balance(tr::now));
@ -708,22 +707,40 @@ not_null<Ui::RpWidget*> AddBalanceWidget(
state->opacity = value;
}, balance->lifetime());
}
const auto diffBetweenStarAndCount = state->count.style()->font->spacew;
const auto resize = [=] {
balance->resize(
std::max(
state->label.maxWidth(),
state->count.maxWidth()
+ starSize.width()
+ diffBetweenStarAndCount),
state->label.style()->font->height + starSize.height());
std::max(state->label.maxWidth(), state->count.maxWidth()),
(state->label.style()->font->height
+ state->count.style()->font->height));
};
std::move(
balanceValue
) | rpl::start_with_next([=](CreditsAmount value) {
state->count.setText(
auto text = TextWithEntities();
const auto manager = &session->data().customEmojiManager();
if (value.ton()) {
text.append(Ui::Text::SingleCustomEmoji(
manager->registerInternalEmoji(
Ui::Earn::IconCurrencyColored(
st::tonFieldIconSize,
st::windowActiveTextFg->c),
st::channelEarnCurrencyLearnMargins,
false))
).append(' ').append(Lang::FormatCreditsAmountDecimal(value));
} else {
text.append(
manager->creditsEmoji()
).append(' ').append(
Lang::FormatCreditsAmountToShort(value).string);
}
state->count.setMarkedText(
st::semiboldTextStyle,
Lang::FormatCreditsAmountToShort(value).string);
text,
kMarkupTextOptions,
Core::TextContext({
.session = session,
.repaint = [=] { balance->update(); },
}));
balance->setBalance(value);
resize();
}, balance->lifetime());
@ -742,22 +759,10 @@ not_null<Ui::RpWidget*> AddBalanceWidget(
});
state->count.draw(p, {
.position = QPoint(
(rightAlign
? (balance->width() - state->count.maxWidth())
: (starSize.width() + diffBetweenStarAndCount)),
state->label.minHeight()
+ (starSize.height() - state->count.minHeight()) / 2),
rightAlign ? (balance->width() - state->count.maxWidth()) : 0,
state->label.minHeight()),
.availableWidth = balance->width(),
});
p.drawImage(
(rightAlign
? (balance->width()
- state->count.maxWidth()
- starSize.width()
- diffBetweenStarAndCount)
: 0),
state->label.minHeight(),
state->star);
}, balance->lifetime());
return balance;
}
@ -2489,6 +2494,7 @@ void SmallBalanceBox(
{
const auto balance = AddBalanceWidget(
content,
&show->session(),
show->session().credits().balanceValue(),
true);
show->session().credits().load(true);

View file

@ -79,6 +79,7 @@ void FillCreditOptions(
[[nodiscard]] not_null<Ui::RpWidget*> AddBalanceWidget(
not_null<Ui::RpWidget*> parent,
not_null<Main::Session*> session,
rpl::producer<CreditsAmount> balanceValue,
bool rightAlign,
rpl::producer<float64> opacityValue = nullptr);

View file

@ -389,7 +389,7 @@ using Order = std::vector<QString>;
{
u"todo"_q,
Entry{
&st::settingsPremiumIconTranslations,
&st::settingsPremiumIconChecklist,
tr::lng_premium_summary_subtitle_todo_lists(),
tr::lng_premium_summary_about_todo_lists(),
PremiumFeature::TodoLists,

View file

@ -1365,7 +1365,7 @@ chatTabsOutlineHorizontal: ChatTabsOutline {
chatTabsOutlineVertical: ChatTabsOutline(chatTabsOutlineHorizontal) {
}
suggestPriceTonIconMargins: margins(0px, 1px, 0px, 0px);
suggestPriceTonIconMargins: margins(0px, 2px, 0px, 0px);
suggestPriceBox: Box(defaultBox) {
buttonPadding: margins(22px, 22px, 22px, 22px);
buttonHeight: 42px;