Add about auction box layout (no icons yet).

This commit is contained in:
John Preston
2025-11-13 14:12:07 +04:00
parent 0e5e4ca7ea
commit cab93600dd
15 changed files with 406 additions and 201 deletions
+2 -2
View File
@@ -4003,8 +4003,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_auction_about_missed_title" = "Missed Bidders";
"lng_auction_about_missed_about" = "If your bid doesn't win after the final round, your Stars will be fully refunded.";
"lng_auction_about_understood" = "Understood";
"lng_auction_text#one" = "Top **{count}** bidder will get 1 {name} this round. {link}";
"lng_auction_text#other" = "Top **{count}** bidders will get 1 {name} this round. {link}";
"lng_auction_text#one" = "Top **{count}** bidder will get {name} gifts this round. {link}";
"lng_auction_text#other" = "Top **{count}** bidders will get {name} gifts this round. {link}";
"lng_auction_text_link" = "Learn more {arrow}";
"lng_auction_text_ended" = "Auction ended.";
"lng_auction_start_label" = "Started";
@@ -9,7 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "boxes/star_gift_box.h"
#include "calls/group/calls_group_common.h"
#include "core/credits_amount.h"
#include "core/ui_integration.h"
#include "data/components/credits.h"
#include "data/components/gift_auctions.h"
#include "data/data_message_reactions.h"
@@ -21,7 +23,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "payments/ui/payments_reaction_box.h"
#include "payments/payments_checkout_process.h"
#include "storage/storage_account.h"
#include "ui/controls/button_labels.h"
#include "ui/controls/feature_list.h"
#include "ui/controls/table_rows.h"
#include "ui/layers/generic_box.h"
#include "ui/text/format_values.h"
@@ -31,13 +35,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/table_layout.h"
#include "ui/dynamic_thumbnails.h"
#include "window/window_session_controller.h"
#include "styles/style_calls.h"
#include "styles/style_chat.h"
#include "styles/style_layers.h"
#include "styles/style_credits.h"
#include "styles/style_info.h"
#include "styles/style_layers.h"
#include "styles/style_menu_icons.h"
namespace Ui {
namespace {
constexpr auto kAuctionAboutShownPref = "gift_auction_about_shown"_cs;
constexpr auto kBidPlacedToastDuration = 5 * crl::time(1000);
[[nodiscard]] rpl::producer<int> MinutesLeftTillValue(TimeId endDate) {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
@@ -71,9 +81,9 @@ namespace {
}
struct AuctionBidBoxArgs {
not_null<PeerData*> peer;
std::shared_ptr<ChatHelpers::Show> show;
rpl::producer<Data::GiftAuctionState> state;
Fn<void(int)> save;
};
void PlaceAuctionBid(
@@ -87,16 +97,14 @@ void PlaceAuctionBid(
const MTPUpdates *updates) {
done(result);
};
const auto invoice = state.my.bid
? MTP_inputInvoiceStarGiftAuctionUpdateBid(
MTP_long(state.gift->id),
MTP_long(amount))
: MTP_inputInvoiceStarGiftAuctionBid(
MTP_flags(0),
to->input,
MTP_long(state.gift->id),
MTP_long(amount),
MTPTextWithEntities());
using Flag = MTPDinputInvoiceStarGiftAuctionBid::Flag;
const auto invoice = MTP_inputInvoiceStarGiftAuctionBid(
MTP_flags((state.my.bid ? Flag::f_update_bid : Flag())
| (state.my.bid ? Flag() : Flag::f_peer)),
state.my.bid ? MTP_inputPeerEmpty() : to->input,
MTP_long(state.gift->id),
MTP_long(amount),
MTPTextWithEntities());
RequestOurForm(show, invoice, [=](
uint64 formId,
CreditsAmount price,
@@ -135,6 +143,28 @@ void AuctionBidBox(not_null<GenericBox*> box, AuctionBidBoxArgs &&args) {
.my = true,
}
};
const auto save = [=, peer = args.peer](int amount) {
const auto &now = state->current();
const auto was = (now.my.bid > 0);
const auto perRound = now.gift->auctionGiftsPerRound;
const auto done = [=](Payments::CheckoutResult result) {
if (result == Payments::CheckoutResult::Paid) {
show->showToast({
.title = (was
? tr::lng_auction_bid_increased_title
: tr::lng_auction_bid_placed_title)(
tr::now),
.text = tr::lng_auction_bid_done_text(
tr::now,
lt_count,
perRound,
tr::rich),
.duration = kBidPlacedToastDuration,
});
}
};
PlaceAuctionBid(show, peer, amount, now, done);
};
PaidReactionsBox(box, {
.min = int(state->current().my.bid
? state->current().my.minBidAmount
@@ -147,7 +177,7 @@ void AuctionBidBox(not_null<GenericBox*> box, AuctionBidBoxArgs &&args) {
.submit = submit,
.colorings = session->appConfig().groupCallColorings(),
.balanceValue = session->credits().balanceValue(),
.send = [weak, save = args.save](int count, uint64 barePeerId) {
.send = [=](int count, uint64 barePeerId) {
save(count);
if (const auto strong = weak.get()) {
strong->closeBox();
@@ -290,8 +320,95 @@ void AuctionBidBox(not_null<GenericBox*> box, AuctionBidBoxArgs &&args) {
void AuctionAboutBox(
not_null<GenericBox*> box,
int rounds,
int giftsPerRound) {
int giftsPerRound,
Fn<void(Fn<void()> close)> understood) {
box->setStyle(st::confcallJoinBox);
box->setWidth(st::boxWideWidth);
box->setNoContentMargin(true);
box->addTopButton(st::boxTitleClose, [=] {
box->closeBox();
});
box->addRow(
Calls::Group::MakeRoundActiveLogo(
box,
st::auctionAboutLogo,
st::auctionAboutLogoPadding),
st::boxRowPadding + st::confcallLinkHeaderIconPadding);
box->addRow(
object_ptr<Ui::FlatLabel>(
box,
tr::lng_auction_about_title(),
st::boxTitle),
st::boxRowPadding + st::confcallLinkTitlePadding,
style::al_top);
box->addRow(
object_ptr<Ui::FlatLabel>(
box,
tr::lng_auction_about_subtitle(tr::rich),
st::confcallLinkCenteredText),
st::boxRowPadding,
style::al_top
)->setTryMakeSimilarLines(true);
const auto features = std::vector<FeatureListEntry>{
{
st::menuIconRatingGifts,
tr::lng_auction_about_top_title(
tr::now,
lt_count,
giftsPerRound),
tr::lng_auction_about_top_about(
tr::now,
lt_count,
giftsPerRound,
lt_rounds,
tr::lng_auction_about_top_rounds(
tr::now,
lt_count,
rounds,
tr::rich),
lt_bidders,
tr::lng_auction_about_top_bidders(
tr::now,
lt_count,
giftsPerRound,
tr::rich),
tr::rich),
},
{
st::menuIconRatingRefund,
tr::lng_auction_about_bid_title(tr::now),
tr::lng_auction_about_bid_about(
tr::now,
lt_count,
giftsPerRound,
tr::rich),
},
{
st::menuIconRatingUsers,
tr::lng_auction_about_missed_title(tr::now),
tr::lng_auction_about_missed_about(tr::now, tr::rich),
},
};
for (const auto &feature : features) {
box->addRow(Ui::MakeFeatureListEntry(box, feature));
}
const auto close = Fn<void()>([weak = base::make_weak(box)] {
if (const auto strong = weak.get()) {
strong->closeBox();
}
});
box->addButton(
rpl::single(QString()),
understood ? [=] { understood(close); } : close
)->setText(rpl::single(Ui::Text::IconEmoji(
&st::infoStarsUnderstood
).append(' ').append(tr::lng_auction_about_understood(tr::now))));
}
void AuctionGotGiftsBox(not_null<GenericBox*> box, int count) {
}
void AuctionInfoBox(
@@ -375,7 +492,7 @@ void AuctionInfoBox(
box->resizeToWidth(box->widthNoMargins());
about->setClickHandlerFilter([=](const auto &...) {
show->show(Box(AuctionAboutBox, rounds, perRound));
show->show(Box(AuctionAboutBox, rounds, perRound, nullptr));
return false;
});
@@ -383,42 +500,46 @@ void AuctionInfoBox(
AuctionInfoTable(box, box->verticalLayout(), state->value.value()),
st::boxRowPadding + st::auctionInfoTableMargin);
state->value.value(
) | rpl::map([=](const Data::GiftAuctionState &state) {
return state.my.gotCount;
}) | rpl::filter(
rpl::mappers::_1 > 0
) | rpl::take(1) | rpl::start_with_next([=](int count) {
box->addRow(
object_ptr<Ui::FlatLabel>(
box,
tr::lng_auction_bought(
lt_count_decimal,
rpl::single(count * 1.),
lt_emoji,
rpl::single(Data::SingleCustomEmoji(
state->value.current().gift->document)),
lt_arrow,
rpl::single(Ui::Text::IconEmoji(&st::textMoreIconEmoji)),
tr::link),
st::uniqueGiftValueAvailableLink,
st::defaultPopupMenu,
Core::TextContext({ .session = &show->session() })),
st::boxRowPadding + st::uniqueGiftValueAvailableMargin,
style::al_top
)->setClickHandlerFilter([=](const auto &...) {
const auto now = state->value.current().my.gotCount;
show->show(Box(AuctionGotGiftsBox, now));
return false;
});
}, box->lifetime());
const auto button = box->addButton(rpl::single(QString()), [=] {
if (state->value.current().finished() || !state->minutesLeft.current()) {
if (state->value.current().finished()
|| !state->minutesLeft.current()) {
box->closeBox();
return;
}
const auto save = [=](int amount) {
const auto &now = state->value.current();
const auto was = (now.my.bid > 0);
const auto perRound = now.gift->auctionGiftsPerRound;
const auto done = [=](Payments::CheckoutResult result) {
if (result == Payments::CheckoutResult::Paid) {
show->showToast({
.title = (was
? tr::lng_auction_bid_increased_title
: tr::lng_auction_bid_placed_title)(
tr::now),
.text = tr::lng_auction_bid_done_text(
tr::now,
lt_count,
perRound,
tr::rich)
});
}
};
PlaceAuctionBid(
show,
peer,
amount,
now,
done);
};
const auto bidBox = show->show(MakeAuctionBidBox({
.peer = peer,
.show = show,
.state = state->value.value(),
.save = save,
}));
bidBox->boxClosing(
) | rpl::start_with_next([=] {
@@ -481,6 +602,59 @@ void AuctionInfoBox(
? st::attentionButtonFg->c
: std::optional<QColor>());
}, box->lifetime());
box->setNoContentMargin(true);
const auto close = CreateChild<IconButton>(
box->verticalLayout(),
st::boxTitleClose);
close->setClickedCallback([=] { box->closeBox(); });
box->verticalLayout()->widthValue() | rpl::start_with_next([=](int) {
close->moveToRight(0, 0);
}, close->lifetime());
}
void ChooseAndShowAuctionBox(
std::shared_ptr<ChatHelpers::Show> show,
not_null<PeerData*> peer,
std::shared_ptr<rpl::variable<Data::GiftAuctionState>> state,
Fn<void()> boxClosed) {
const auto local = &peer->session().local();
const auto &now = state->current();
const auto finished = now.finished()
|| (now.endDate <= base::unixtime::now());
const auto showBidBox = now.my.bid && !finished;
const auto showInfoBox = !showBidBox
&& (local->readPref<bool>(kAuctionAboutShownPref) || finished);
auto box = base::weak_qptr<BoxContent>();
if (showBidBox) {
box = show->show(MakeAuctionBidBox({
.peer = peer,
.show = show,
.state = state->value(),
}));
} else if (showInfoBox) {
box = show->show(Box(
AuctionInfoBox,
show,
peer,
state->value()));
} else {
local->writePref<bool>(kAuctionAboutShownPref, true);
const auto understood = [=](Fn<void()> close) {
ChooseAndShowAuctionBox(show, peer, state, close);
};
box = show->show(Box(
AuctionAboutBox,
now.totalRounds,
now.gift->auctionGiftsPerRound,
understood));
}
if (const auto strong = box.get()) {
strong->boxClosing(
) | rpl::start_with_next(boxClosed, strong->lifetime());
} else {
boxClosed();
}
}
} // namespace
@@ -506,13 +680,10 @@ rpl::lifetime ShowStarGiftAuction(
(*value) = std::move(state);
if (initial) {
if (const auto strong = weak.get()) {
const auto box = strong->show(Box(
AuctionInfoBox,
strong->uiShow(),
peer,
value->value()));
box->boxClosing(
) | rpl::start_with_next(boxClosed, box->lifetime());
const auto show = strong->uiShow();
ChooseAndShowAuctionBox(show, peer, value, boxClosed);
} else {
boxClosed();
}
}
});
+1
View File
@@ -1593,6 +1593,7 @@ confcallLinkButton: RoundButton(defaultActiveButton) {
confcallLinkBoxInitial: Box(defaultBox) {
buttonPadding: margins(12px, 11px, 24px, 96px);
buttonHeight: 42px;
buttonWide: true;
button: confcallLinkButton;
shadowIgnoreTopSkip: true;
}
@@ -77,13 +77,16 @@ object_ptr<Ui::GenericBox> ScreenSharingPrivacyRequestBox() {
#endif // Q_OS_MAC
}
object_ptr<Ui::RpWidget> MakeJoinCallLogo(not_null<QWidget*> parent) {
const auto logoSize = st::confcallJoinLogo.size();
const auto logoOuter = logoSize.grownBy(st::confcallJoinLogoPadding);
object_ptr<Ui::RpWidget> MakeRoundActiveLogo(
not_null<QWidget*> parent,
const style::icon &icon,
const style::margins &padding) {
const auto logoSize = icon.size();
const auto logoOuter = logoSize.grownBy(padding);
auto result = object_ptr<Ui::RpWidget>(parent);
const auto logo = result.data();
logo->resize(logo->width(), logoOuter.height());
logo->paintRequest() | rpl::start_with_next([=] {
logo->paintRequest() | rpl::start_with_next([=, &icon] {
if (logo->width() < logoOuter.width()) {
return;
}
@@ -94,11 +97,18 @@ object_ptr<Ui::RpWidget> MakeJoinCallLogo(not_null<QWidget*> parent) {
p.setBrush(st::windowBgActive);
p.setPen(Qt::NoPen);
p.drawEllipse(outer);
st::confcallJoinLogo.paintInCenter(p, outer);
icon.paintInCenter(p, outer);
}, logo->lifetime());
return result;
}
object_ptr<Ui::RpWidget> MakeJoinCallLogo(not_null<QWidget*> parent) {
return MakeRoundActiveLogo(
parent,
st::confcallJoinLogo,
st::confcallJoinLogoPadding);
}
void ConferenceCallJoinConfirm(
not_null<Ui::GenericBox*> box,
std::shared_ptr<Data::GroupCall> call,
@@ -162,6 +162,10 @@ using StickedTooltips = base::flags<StickedTooltip>;
[[nodiscard]] object_ptr<Ui::GenericBox> ScreenSharingPrivacyRequestBox();
[[nodiscard]] object_ptr<Ui::RpWidget> MakeRoundActiveLogo(
not_null<QWidget*> parent,
const style::icon &icon,
const style::margins &padding);
[[nodiscard]] object_ptr<Ui::RpWidget> MakeJoinCallLogo(
not_null<QWidget*> parent);
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "settings/settings_premium.h"
#include "ui/controls/feature_list.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
@@ -40,12 +41,6 @@ struct State {
bool premium = false;
};
struct Feature {
const style::icon &icon;
QString title;
TextWithEntities about;
};
[[nodiscard]] Ui::Toast::Config ToastAlready(TimeId left) {
return {
.title = tr::lng_stealth_mode_already_title(tr::now),
@@ -134,7 +129,7 @@ struct Feature {
}) | rpl::flatten_latest();
}
[[nodiscard]] Feature FeaturePast() {
[[nodiscard]] Ui::FeatureListEntry FeaturePast() {
return {
.icon = st::storiesStealthFeaturePastIcon,
.title = tr::lng_stealth_mode_past_title(tr::now),
@@ -142,7 +137,7 @@ struct Feature {
};
}
[[nodiscard]] Feature FeatureNext() {
[[nodiscard]] Ui::FeatureListEntry FeatureNext() {
return {
.icon = st::storiesStealthFeatureNextIcon,
.title = tr::lng_stealth_mode_next_title(tr::now),
@@ -202,45 +197,6 @@ struct Feature {
st::storiesStealthAboutMargin);
}
[[nodiscard]] object_ptr<Ui::RpWidget> MakeFeature(
QWidget *parent,
Feature feature) {
auto result = object_ptr<Ui::PaddingWrap<>>(
parent,
object_ptr<Ui::RpWidget>(parent),
st::storiesStealthFeatureMargin);
const auto widget = result->entity();
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
widget,
feature.icon,
st::storiesStealthFeatureIconPosition);
const auto title = Ui::CreateChild<Ui::FlatLabel>(
widget,
feature.title,
st::storiesStealthFeatureTitle);
const auto about = Ui::CreateChild<Ui::FlatLabel>(
widget,
rpl::single(feature.about),
st::storiesStealthFeatureAbout);
icon->show();
title->show();
about->show();
widget->widthValue(
) | rpl::start_with_next([=](int width) {
const auto left = st::storiesStealthFeatureLabelLeft;
const auto available = width - left;
title->resizeToWidth(available);
about->resizeToWidth(available);
auto top = 0;
title->move(left, top);
top += title->height() + st::storiesStealthFeatureSkip;
about->move(left, top);
top += about->height();
widget->resize(width, top);
}, widget->lifetime());
return result;
}
[[nodiscard]] object_ptr<Ui::RoundButton> MakeButton(
QWidget *parent,
rpl::producer<State> state) {
@@ -329,9 +285,17 @@ struct Feature {
box->addRow(MakeLogo(box));
box->addRow(MakeTitle(box), style::al_top);
box->addRow(MakeAbout(box, data->state.value()), style::al_top);
box->addRow(MakeFeature(box, FeaturePast()));
const auto make = [&](const Ui::FeatureListEntry &entry) {
return Ui::MakeFeatureListEntry(
box,
entry,
{},
st::storiesStealthFeatureTitle,
st::storiesStealthFeatureAbout);
};
box->addRow(make(FeaturePast()));
box->addRow(
MakeFeature(box, FeatureNext()),
make(FeatureNext()),
(st::boxRowPadding
+ QMargins(0, 0, 0, st::storiesStealthBoxBottom)));
box->setNoContentMargin(true);
@@ -1093,8 +1093,6 @@ storiesStealthFeatureAbout: FlatLabel(defaultFlatLabel) {
}
storiesStealthFeaturePastIcon: icon{{ "stories/stealth_5m", storiesComposeBlue }};
storiesStealthFeatureNextIcon: icon{{ "stories/stealth_25m", storiesComposeBlue }};
storiesStealthFeatureIconPosition: point(3px, 7px);
storiesStealthFeatureMargin: margins(0px, 8px, 0px, 6px);
storiesStealthFeatureLabelLeft: 46px;
storiesStealthFeatureSkip: 2px;
storiesStealthBoxBottom: 11px;
+1 -2
View File
@@ -1524,8 +1524,7 @@ inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:I
inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice;
inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice;
inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice;
inputInvoiceStarGiftAuctionBid#77d28da6 flags:# hide_name:flags.0?true peer:InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice;
inputInvoiceStarGiftAuctionUpdateBid#85275c98 gift_id:long bid_amount:long = InputInvoice;
inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice;
payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice;
@@ -2438,7 +2438,7 @@ void UniqueGiftValueBox(
platform(Ui::Text::WithEntities),
lt_arrow,
rpl::single(Ui::Text::IconEmoji(&st::textMoreIconEmoji)),
[](const QString &text) { return Ui::Text::Link(text); }),
tr::link),
st::uniqueGiftValueAvailableLink,
st::defaultPopupMenu,
Core::TextContext({ .session = &show->session() })),
@@ -3676,19 +3676,6 @@ Webview::StorageId TonSiteStorageId() {
return result;
}
template <>
std::optional<bool> Account::readPrefImpl<bool>(std::string_view key) {
if (const auto data = readPrefGeneric(key)) {
return !data->isEmpty();
}
return {};
}
template <>
void Account::writePrefImpl<bool>(std::string_view key, bool value) {
writePrefGeneric(key, value ? "\x1"_q : QByteArray());
}
void Account::clearPref(std::string_view key) {
const auto i = _prefs.find(QByteArray(key.data(), key.size()));
if (i == end(_prefs)) {
@@ -3790,4 +3777,18 @@ void Account::readPrefs() {
_prefs = std::move(map);
}
// Define your own pref types in the similar way.
template <>
std::optional<bool> Account::readPrefImpl<bool>(std::string_view key) {
if (const auto data = readPrefGeneric(key)) {
return !data->isEmpty();
}
return {};
}
template <>
void Account::writePrefImpl<bool>(std::string_view key, bool value) {
writePrefGeneric(key, value ? "\x1"_q : QByteArray());
}
} // namespace Storage
@@ -0,0 +1,61 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/controls/feature_list.h"
#include "base/object_ptr.h"
#include "info/profile/info_profile_icon.h"
#include "ui/widgets/labels.h"
#include "styles/style_info.h"
namespace Ui {
object_ptr<RpWidget> MakeFeatureListEntry(
QWidget *parent,
FeatureListEntry feature,
const Text::MarkedContext &context,
const style::FlatLabel &stTitle,
const style::FlatLabel &stAbout) {
auto result = object_ptr<PaddingWrap<>>(
parent,
object_ptr<RpWidget>(parent),
st::infoStarsFeatureMargin);
const auto widget = result->entity();
const auto icon = CreateChild<Info::Profile::FloatingIcon>(
widget,
feature.icon,
st::infoStarsFeatureIconPosition);
const auto title = CreateChild<FlatLabel>(
widget,
feature.title,
stTitle);
const auto about = CreateChild<FlatLabel>(
widget,
rpl::single(feature.about),
stAbout,
st::defaultPopupMenu,
context);
icon->show();
title->show();
about->show();
widget->widthValue(
) | rpl::start_with_next([=](int width) {
const auto left = st::infoStarsFeatureLabelLeft;
const auto available = width - left;
title->resizeToWidth(available);
about->resizeToWidth(available);
auto top = 0;
title->move(left, top);
top += title->height() + st::infoStarsFeatureSkip;
about->move(left, top);
top += about->height();
widget->resize(width, top);
}, widget->lifetime());
return result;
}
} // namespace Ui
@@ -0,0 +1,40 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace style {
struct FlatLabel;
} // namespace style
namespace st {
extern const style::FlatLabel &infoStarsFeatureTitle;
extern const style::FlatLabel &infoStarsFeatureAbout;
} // namespace st
namespace Ui::Text {
struct MarkedContext;
} // namespace Ui::Text
namespace Ui {
class RpWidget;
struct FeatureListEntry {
const style::icon &icon;
QString title;
TextWithEntities about;
};
[[nodiscard]] object_ptr<RpWidget> MakeFeatureListEntry(
QWidget *parent,
FeatureListEntry feature,
const Text::MarkedContext &context = {},
const style::FlatLabel &stTitle = st::infoStarsFeatureTitle,
const style::FlatLabel &stAbout = st::infoStarsFeatureAbout);
} // namespace Ui
@@ -8,8 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/stars_rating.h"
#include "base/unixtime.h"
#include "info/profile/info_profile_icon.h"
#include "lang/lang_keys.h"
#include "ui/controls/feature_list.h"
#include "ui/effects/premium_bubble.h"
#include "ui/effects/premium_graphics.h"
#include "ui/layers/generic_box.h"
@@ -41,54 +41,6 @@ constexpr auto kAutoCollapseTimeout = 4 * crl::time(1000);
using Counters = Data::StarsRating;
struct Feature {
const style::icon &icon;
QString title;
TextWithEntities about;
};
[[nodiscard]] object_ptr<Ui::RpWidget> MakeFeature(
QWidget *parent,
Feature feature,
const Text::MarkedContext &context) {
auto result = object_ptr<Ui::PaddingWrap<>>(
parent,
object_ptr<Ui::RpWidget>(parent),
st::infoStarsFeatureMargin);
const auto widget = result->entity();
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
widget,
feature.icon,
st::infoStarsFeatureIconPosition);
const auto title = Ui::CreateChild<Ui::FlatLabel>(
widget,
feature.title,
st::infoStarsFeatureTitle);
const auto about = Ui::CreateChild<Ui::FlatLabel>(
widget,
rpl::single(feature.about),
st::infoStarsFeatureAbout,
st::defaultPopupMenu,
context);
icon->show();
title->show();
about->show();
widget->widthValue(
) | rpl::start_with_next([=](int width) {
const auto left = st::infoStarsFeatureLabelLeft;
const auto available = width - left;
title->resizeToWidth(available);
about->resizeToWidth(available);
auto top = 0;
title->move(left, top);
top += title->height() + st::infoStarsFeatureSkip;
about->move(left, top);
top += about->height();
widget->resize(width, top);
}, widget->lifetime());
return result;
}
[[nodiscard]] Counters AdjustByReached(Counters data) {
if (data.stars < 0) {
return data;
@@ -111,7 +63,7 @@ struct Feature {
return data;
}
[[nodiscard]] Fn<Ui::Premium::BubbleText(int)> BubbleTextFactory(
[[nodiscard]] Fn<Premium::BubbleText(int)> BubbleTextFactory(
int countForScale,
int nextLevelCounter) {
return [=](int count) {
@@ -122,7 +74,7 @@ struct Feature {
? (Lang::FormatCountDecimal((count / 100) / 10.) + 'K')
: (Lang::FormatCountDecimal((count / 100'000) / 10.) + 'M');
};
return Ui::Premium::BubbleText{
return Premium::BubbleText{
.counter = counter(count),
.additional = (nextLevelCounter
? (u"/"_q + counter(nextLevelCounter))
@@ -141,7 +93,7 @@ void FillRatingLimit(
int nextLevelStars,
bool hideCount) {
const auto addSkip = [&](int skip) {
container->add(object_ptr<Ui::FixedHeightWidget>(container, skip));
container->add(object_ptr<FixedHeightWidget>(container, skip));
};
const auto negative = (type == Premium::BubbleType::NegativeRating);
@@ -203,7 +155,7 @@ void FillRatingLimit(
rpl::duplicate(bubbleRowState),
type,
(hideCount
? [](int) { return Ui::Premium::BubbleText(); }
? [](int) { return Premium::BubbleText(); }
: BubbleTextFactory(starsForScale, nextLevelStars)),
negative ? &st::levelNegativeBubble : &st::infoStarsCrown,
limitLinePadding);
@@ -287,22 +239,22 @@ void AboutRatingBox(
? tr::lng_stars_rating_about(
lt_name,
rpl::single(TextWithEntities{ name }),
Ui::Text::RichLangValue) | rpl::type_erased()
Text::RichLangValue) | rpl::type_erased()
: tr::lng_stars_rating_about_your(
Ui::Text::RichLangValue) | rpl::type_erased();
Text::RichLangValue) | rpl::type_erased();
if (data.level < 0) {
auto text = (data.stars < 0)
? tr::lng_stars_rating_negative_your(
lt_count_decimal,
rpl::single(-data.stars * 1.),
Ui::Text::RichLangValue)
Text::RichLangValue)
: tr::lng_stars_rating_negative(
lt_name,
rpl::single(TextWithEntities{ name }),
Ui::Text::RichLangValue);
Text::RichLangValue);
box->addRow(
object_ptr<Ui::FlatLabel>(
object_ptr<FlatLabel>(
box,
std::move(text),
st::boostTextNegative),
@@ -313,7 +265,7 @@ void AboutRatingBox(
}
box->addRow(
object_ptr<Ui::FlatLabel>(box, std::move(title), st::infoStarsTitle),
object_ptr<FlatLabel>(box, std::move(title), st::infoStarsTitle),
st::boxRowPadding + QMargins(0, st::boostTitleSkip / 2, 0, 0),
style::al_top);
@@ -331,17 +283,17 @@ void AboutRatingBox(
tr::lng_stars_rating_updates(tr::now, lt_count, days),
},
lt_link,
Ui::Text::Link((value
Text::Link((value
? tr::lng_stars_rating_pending_back
: tr::lng_stars_rating_pending_preview)(
tr::now,
lt_arrow,
Ui::Text::IconEmoji(&st::textMoreIconEmoji),
Ui::Text::WithEntities)),
Ui::Text::RichLangValue);
Text::IconEmoji(&st::textMoreIconEmoji),
Text::WithEntities)),
Text::RichLangValue);
});
const auto aboutPending = box->addRow(
object_ptr<Ui::FlatLabel>(
object_ptr<FlatLabel>(
box,
std::move(text),
st::boostTextPending),
@@ -360,7 +312,7 @@ void AboutRatingBox(
}
box->addRow(
object_ptr<Ui::FlatLabel>(
object_ptr<FlatLabel>(
box,
std::move(text),
st::boostText),
@@ -369,12 +321,12 @@ void AboutRatingBox(
style::al_top
)->setTryMakeSimilarLines(true);
auto helper = Ui::Text::CustomEmojiHelper();
auto helper = Text::CustomEmojiHelper();
const auto makeBadge = [&](
const QString &text,
const style::RoundButton &st) {
return helper.paletteDependent(
Ui::Text::CustomEmojiTextBadge(text, st));
Text::CustomEmojiTextBadge(text, st));
};
const auto makeActive = [&](const QString &text) {
return makeBadge(text, st::customEmojiTextBadge);
@@ -382,7 +334,7 @@ void AboutRatingBox(
const auto makeInactive = [&](const QString &text) {
return makeBadge(text, st::infoRatingDeductedBadge);
};
const auto features = std::vector<Feature>{
const auto features = std::vector<FeatureListEntry>{
{
st::menuIconRatingGifts,
tr::lng_stars_title_gifts_telegram(tr::now),
@@ -390,7 +342,7 @@ void AboutRatingBox(
tr::now,
lt_emoji,
makeActive(tr::lng_stars_rating_added(tr::now)),
Ui::Text::RichLangValue),
Text::RichLangValue),
},
{
st::menuIconRatingUsers,
@@ -399,7 +351,7 @@ void AboutRatingBox(
tr::now,
lt_emoji,
makeActive(tr::lng_stars_rating_added(tr::now)),
Ui::Text::RichLangValue),
Text::RichLangValue),
},
{
st::menuIconRatingRefund,
@@ -408,16 +360,16 @@ void AboutRatingBox(
tr::now,
lt_emoji,
makeInactive(tr::lng_stars_rating_deducted(tr::now)),
Ui::Text::RichLangValue),
Text::RichLangValue),
},
};
const auto context = helper.context();
for (const auto &feature : features) {
box->addRow(MakeFeature(box, feature, context));
box->addRow(MakeFeatureListEntry(box, feature, context));
}
box->addButton(rpl::single(QString()), [=] {
box->closeBox();
})->setText(rpl::single(Ui::Text::IconEmoji(
})->setText(rpl::single(Text::IconEmoji(
&st::infoStarsUnderstood
).append(' ').append(tr::lng_stars_rating_understood(tr::now))));
}
@@ -462,11 +414,11 @@ void AboutRatingBox(
StarsRating::StarsRating(
QWidget *parent,
std::shared_ptr<Ui::Show> show,
std::shared_ptr<Show> show,
const QString &name,
rpl::producer<Counters> value,
Fn<Data::StarsRatingPending()> pending)
: _widget(std::make_unique<Ui::AbstractButton>(parent))
: _widget(std::make_unique<AbstractButton>(parent))
, _show(std::move(show))
, _name(name)
, _value(std::move(value))
@@ -281,7 +281,7 @@ uniqueGiftResalePadding: margins(4px, 4px, 8px, 4px);
uniqueGiftResaleMargin: margins(10px, 10px, 10px, 10px);
uniqueGiftTitleTop: 140px;
uniqueGiftSubtitle: FlatLabel(defaultFlatLabel) {
minWidth: 256px;
minWidth: 64px;
align: align(top);
}
uniqueGiftReleasedBy: FlatLabel(uniqueGiftSubtitle) {
@@ -444,3 +444,5 @@ videoStreamStarsCover: PremiumCover(creditsLowBalancePremiumCover) {
auctionInfoPreviewMargin: margins(0px, 24px, 0px, 8px);
auctionInfoSubtitleSkip: 8px;
auctionInfoTableMargin: margins(0px, 12px, 0px, 12px);
auctionAboutLogo: icon {{ "calls/group_call_logo", windowFgActive }};
auctionAboutLogoPadding: margins(8px, 8px, 8px, 8px);
+2
View File
@@ -391,6 +391,8 @@ PRIVATE
ui/controls/download_bar.h
ui/controls/emoji_button.cpp
ui/controls/emoji_button.h
ui/controls/feature_list.cpp
ui/controls/feature_list.h
ui/controls/filter_link_header.cpp
ui/controls/filter_link_header.h
ui/controls/jump_down_button.cpp