mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Add about auction box layout (no icons yet).
This commit is contained in:
@@ -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,13 +97,11 @@ 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,
|
||||
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());
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user