Boost community features list.

This commit is contained in:
John Preston 2024-02-07 12:20:59 +04:00
parent ea12c2f62c
commit 680171226c
40 changed files with 401 additions and 59 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -2155,27 +2155,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_boost_again_button" = "Boost Again";
"lng_boost_level#one" = "Level {count}";
"lng_boost_level#other" = "Level {count}";
"lng_boost_level_unlocks#one" = "Level {count} Unlocks:";
"lng_boost_level_unlocks#other" = "Level {count} Unlocks:";
"lng_boost_channel_title_first" = "Enable stories for channel";
"lng_boost_channel_title_first_group" = "Enable stories for group";
"lng_boost_channel_needs_first#one" = "{channel} needs **{count}** more boost to enable posting stories. Help make it possible!";
"lng_boost_channel_needs_first#other" = "{channel} needs **{count}** more boosts to enable posting stories. Help make it possible!";
"lng_boost_channel_needs_unlock#one" = "{channel} needs **{count}** more boost to unlock new features.";
"lng_boost_channel_needs_unlock#other" = "{channel} needs **{count}** more boosts to unlock new features.";
//"lng_boost_channel_needs_first#one" = "{channel} needs **{count}** more boost to enable posting stories. Help make it possible!";
//"lng_boost_channel_needs_first#other" = "{channel} needs **{count}** more boosts to enable posting stories. Help make it possible!";
"lng_boost_channel_title_more" = "Help upgrade channel";
"lng_boost_channel_title_more_group" = "Help upgrade group";
"lng_boost_channel_needs_more#one" = "{channel} needs **{count}** more boost to be able to {post}.";
"lng_boost_channel_needs_more#other" = "{channel} needs **{count}** more boosts to be able to {post}.";
//"lng_boost_channel_needs_more#one" = "{channel} needs **{count}** more boost to be able to {post}.";
//"lng_boost_channel_needs_more#other" = "{channel} needs **{count}** more boosts to be able to {post}.";
"lng_boost_channel_title_max" = "Maximum level reached";
"lng_boost_channel_you_title" = "You boosted {channel}!";
"lng_boost_channel_you_first#one" = "This channel needs **{count}** more boost\nto enable stories.";
"lng_boost_channel_you_first#other" = "This channel needs **{count}** more boosts\nto enable stories.";
"lng_boost_channel_you_more#one" = "This channel needs **{count}** more boost\nto be able to {post}.";
"lng_boost_channel_you_more#other" = "This channel needs **{count}** more boosts\nto be able to {post}.";
//"lng_boost_channel_you_first#one" = "This channel needs **{count}** more boost\nto enable stories.";
//"lng_boost_channel_you_first#other" = "This channel needs **{count}** more boosts\nto enable stories.";
//"lng_boost_channel_you_more#one" = "This channel needs **{count}** more boost\nto be able to {post}.";
//"lng_boost_channel_you_more#other" = "This channel needs **{count}** more boosts\nto be able to {post}.";
"lng_boost_channel_reached_first" = "This channel reached **Level 1** and can now post stories.";
"lng_boost_channel_reached_more#one" = "This channel reached **Level {count}** and can now {post}.";
"lng_boost_channel_reached_more#other" = "This channel reached **Level {count}** and can now {post}.";
"lng_boost_channel_you_first_group#one" = "This group needs **{count}** more boost\nto enable stories.";
"lng_boost_channel_you_first_group#other" = "This group needs **{count}** more boosts\nto enable stories.";
"lng_boost_channel_you_more_group#one" = "This group needs **{count}** more boost\nto be able to {post}.";
"lng_boost_channel_you_more_group#other" = "This group needs **{count}** more boosts\nto be able to {post}.";
//"lng_boost_channel_you_first_group#one" = "This group needs **{count}** more boost\nto enable stories.";
//"lng_boost_channel_you_first_group#other" = "This group needs **{count}** more boosts\nto enable stories.";
//"lng_boost_channel_you_more_group#one" = "This group needs **{count}** more boost\nto be able to {post}.";
//"lng_boost_channel_you_more_group#other" = "This group needs **{count}** more boosts\nto be able to {post}.";
"lng_boost_channel_reached_first_group" = "This group reached **Level 1** and can now post stories.";
"lng_boost_channel_reached_more_group#one" = "This group reached **Level {count}** and can now {post}.";
"lng_boost_channel_reached_more_group#other" = "This group reached **Level {count}** and can now {post}.";
@ -2241,6 +2245,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_boost_channel_gifting" = "Boost your channel by gifting your subscribers Telegram Premium. {link}";
"lng_boost_channel_gifting_link" = "Get boosts >";
"lng_feature_stories#one" = "**{count}** Story Per Day";
"lng_feature_stories#other" = "**{count}** Stories Per Day";
"lng_feature_reactions#one" = "**{count}** Custom Reaction";
"lng_feature_reactions#other" = "**{count}** Custom Reactions";
"lng_feature_name_color_channel#one" = "**{count}** Channel Name Color";
"lng_feature_name_color_channel#other" = "**{count}** Channel Name Colors";
"lng_feature_link_style_channel#one" = "**{count}** Style for Links and Quotes";
"lng_feature_link_style_channel#other" = "**{count}** Styles for Links and Quotes";
"lng_feature_link_emoji" = "Custom Logo for Links and Quotes";
"lng_feature_emoji_status" = "**1000+** Emoji Statuses";
"lng_feature_backgrounds_channel#one" = "**{count}** Channel Background";
"lng_feature_backgrounds_channel#other" = "**{count}** Channel Backgrounds";
"lng_feature_custom_background_channel" = "Custom Channel Background";
"lng_feature_backgrounds_group#one" = "**{count}** Group Background";
"lng_feature_backgrounds_group#other" = "**{count}** Group Backgrounds";
"lng_feature_custom_background_group" = "Custom Group Background";
"lng_feature_custom_emoji_pack" = "Custom Emoji Pack";
"lng_feature_transcribe" = "Voice-to-Text Conversion";
"lng_giveaway_new_title" = "Boosts via Gifts";
"lng_giveaway_new_about" = "Get more boosts for your channel by gifting Premium to your subscribers.";
"lng_giveaway_new_about_group" = "Get more boosts for your group by gifting Premium to your subscribers.";

View file

@ -55,19 +55,42 @@ rpl::producer<std::vector<uint8>> PeerColors::suggestedValue() const {
auto PeerColors::indicesValue() const
-> rpl::producer<Ui::ColorIndicesCompressed> {
return rpl::single(_colorIndicesCurrent
? *_colorIndicesCurrent
: Ui::ColorIndicesCompressed()
return rpl::single(
indicesCurrent()
) | rpl::then(_colorIndicesChanged.events() | rpl::map([=] {
return *_colorIndicesCurrent;
return indicesCurrent();
}));
}
int PeerColors::requiredLevelFor(PeerId channel, uint8 index) const {
Ui::ColorIndicesCompressed PeerColors::indicesCurrent() const {
return _colorIndicesCurrent
? *_colorIndicesCurrent
: Ui::ColorIndicesCompressed();
}
const base::flat_map<uint8, int> &PeerColors::requiredLevelsGroup() const {
return _requiredLevelsGroup;
}
const base::flat_map<uint8, int> &PeerColors::requiredLevelsChannel() const {
return _requiredLevelsChannel;
}
int PeerColors::requiredGroupLevelFor(PeerId channel, uint8 index) const {
if (Data::DecideColorIndex(channel) == index) {
return 0;
} else if (const auto i = _requiredLevels.find(index)
; i != end(_requiredLevels)) {
} else if (const auto i = _requiredLevelsGroup.find(index)
; i != end(_requiredLevelsGroup)) {
return i->second;
}
return 1;
}
int PeerColors::requiredChannelLevelFor(PeerId channel, uint8 index) const {
if (Data::DecideColorIndex(channel) == index) {
return 0;
} else if (const auto i = _requiredLevelsChannel.find(index)
; i != end(_requiredLevelsChannel)) {
return i->second;
}
return 1;
@ -100,7 +123,8 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
};
const auto &list = data.vcolors().v;
_requiredLevels.clear();
_requiredLevelsGroup.clear();
_requiredLevelsChannel.clear();
suggested.reserve(list.size());
for (const auto &color : list) {
const auto &data = color.data();
@ -110,8 +134,11 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
continue;
}
const auto colorIndex = uint8(colorIndexBare);
if (const auto min = data.vgroup_min_level()) {
_requiredLevelsGroup[colorIndex] = min->v;
}
if (const auto min = data.vchannel_min_level()) {
_requiredLevels[colorIndex] = min->v;
_requiredLevelsChannel[colorIndex] = min->v;
}
if (!data.is_hidden()) {
suggested.push_back(colorIndex);

View file

@ -25,10 +25,19 @@ public:
[[nodiscard]] std::vector<uint8> suggested() const;
[[nodiscard]] rpl::producer<std::vector<uint8>> suggestedValue() const;
[[nodiscard]] Ui::ColorIndicesCompressed indicesCurrent() const;
[[nodiscard]] auto indicesValue() const
-> rpl::producer<Ui::ColorIndicesCompressed>;
[[nodiscard]] int requiredLevelFor(
[[nodiscard]] auto requiredLevelsGroup() const
-> const base::flat_map<uint8, int> &;
[[nodiscard]] auto requiredLevelsChannel() const
-> const base::flat_map<uint8, int> &;
[[nodiscard]] int requiredGroupLevelFor(
PeerId channel,
uint8 index) const;
[[nodiscard]] int requiredChannelLevelFor(
PeerId channel,
uint8 index) const;
@ -42,7 +51,8 @@ private:
mtpRequestId _requestId = 0;
base::Timer _timer;
rpl::variable<std::vector<uint8>> _suggested;
base::flat_map<uint8, int> _requiredLevels;
base::flat_map<uint8, int> _requiredLevelsGroup;
base::flat_map<uint8, int> _requiredLevelsChannel;
rpl::event_stream<> _colorIndicesChanged;
std::unique_ptr<Ui::ColorIndicesCompressed> _colorIndicesCurrent;

View file

@ -527,9 +527,13 @@ void Apply(
} else {
CheckBoostLevel(show, peer, [=](int level) {
const auto peerColors = &peer->session().api().peerColors();
const auto colorRequired = peerColors->requiredLevelFor(
peer->id,
values.colorIndex);
const auto colorRequired = peer->isMegagroup()
? peerColors->requiredGroupLevelFor(
peer->id,
values.colorIndex)
: peerColors->requiredChannelLevelFor(
peer->id,
values.colorIndex);
const auto iconRequired = values.backgroundEmojiId
? session->account().appConfig().get<int>(
"channel_bg_icon_level_min",

View file

@ -7,10 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peers/replace_boost_box.h"
#include "api/api_peer_colors.h"
#include "apiwrap.h"
#include "base/event_filter.h"
#include "base/unixtime.h"
#include "boxes/peer_list_box.h"
#include "data/data_channel.h"
#include "data/data_cloud_themes.h"
#include "data/data_session.h"
#include "lang/lang_keys.h"
#include "main/main_account.h"
@ -419,6 +422,47 @@ Ui::BoostCounters ParseBoostCounters(
};
}
Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
const auto group = channel->isMegagroup();
const auto appConfig = &channel->session().account().appConfig();
const auto get = [&](const QString &key, int fallback, bool ok = true) {
return ok ? appConfig->get<int>(key, fallback) : 0;
};
auto nameColorsByLevel = base::flat_map<int, int>();
auto linkStylesByLevel = base::flat_map<int, int>();
const auto peerColors = &channel->session().api().peerColors();
const auto &list = group
? peerColors->requiredLevelsGroup()
: peerColors->requiredLevelsChannel();
const auto indices = peerColors->indicesCurrent();
for (const auto &[index, level] : list) {
if (!Ui::ColorPatternIndex(indices, index, false)) {
++nameColorsByLevel[level];
}
++linkStylesByLevel[level];
}
return Ui::BoostFeatures{
.nameColorsByLevel = std::move(nameColorsByLevel),
.linkStylesByLevel = std::move(linkStylesByLevel),
.linkLogoLevel = get(u"channel_bg_icon_level_min"_q, 4, !group),
.transcribeLevel = get(u"group_transcribe_level_min"_q, 6, group),
.emojiPackLevel = get(u"group_emoji_stickers_level_min"_q, 4, group),
.emojiStatusLevel = get(group
? u"group_emoji_status_level_min"_q
: u"channel_emoji_status_level_min"_q, 8),
.wallpaperLevel = get(group
? u"group_wallpaper_level_min"_q
: u"channel_wallpaper_level_min"_q, 9),
.wallpapersCount = int(
channel->owner().cloudThemes().chatThemes().size()),
.customWallpaperLevel = get(group
? u"channel_custom_wallpaper_level_min"_q
: u"group_custom_wallpaper_level_min"_q, 10),
};
}
int BoostsForGift(not_null<Main::Session*> session) {
const auto key = u"boosts_per_sent_gift"_q;
return session->account().appConfig().get<int>(key, 0);

View file

@ -9,12 +9,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/object_ptr.h"
class ChannelData;
namespace Main {
class Session;
} // namespace Main
namespace Ui {
struct BoostCounters;
struct BoostFeatures;
class BoxContent;
class RpWidget;
} // namespace Ui
@ -39,6 +42,9 @@ struct ForChannelBoostSlots {
[[nodiscard]] Ui::BoostCounters ParseBoostCounters(
const MTPpremium_BoostsStatus &status);
[[nodiscard]] Ui::BoostFeatures LookupBoostFeatures(
not_null<ChannelData*> channel);
[[nodiscard]] int BoostsForGift(not_null<Main::Session*> session);
object_ptr<Ui::BoxContent> ReassignBoostsBox(

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/boxes/boost_box.h"
#include "info/profile/info_profile_icon.h"
#include "lang/lang_keys.h"
#include "ui/boxes/confirm_box.h"
#include "ui/effects/fireworks_animation.h"
@ -14,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/painter.h"
#include "styles/style_giveaway.h"
#include "styles/style_layers.h"
@ -45,10 +47,11 @@ namespace {
}
[[nodiscard]] object_ptr<Ui::RpWidget> MakeTitle(
not_null<Ui::GenericBox*> box,
not_null<Ui::RpWidget*> parent,
rpl::producer<QString> title,
rpl::producer<QString> repeated) {
auto result = object_ptr<Ui::RpWidget>(box);
rpl::producer<QString> repeated,
bool centered = true) {
auto result = object_ptr<Ui::RpWidget>(parent);
struct State {
not_null<Ui::FlatLabel*> title;
@ -57,7 +60,7 @@ namespace {
const auto notEmpty = [](const QString &text) {
return !text.isEmpty();
};
const auto state = box->lifetime().make_state<State>(State{
const auto state = parent->lifetime().make_state<State>(State{
.title = Ui::CreateChild<Ui::FlatLabel>(
result.data(),
rpl::duplicate(title),
@ -83,7 +86,9 @@ namespace {
const auto available = outer - repeated - skip;
const auto use = std::min(state->title->textMaxWidth(), available);
state->title->resizeToWidth(use);
const auto left = (outer - use - skip - repeated) / 2;
const auto left = centered
? (outer - use - skip - repeated) / 2
: 0;
state->title->moveToLeft(left, 0);
const auto mleft = st::boostTitleBadge.margin.left();
const auto mtop = st::boostTitleBadge.margin.top();
@ -103,6 +108,171 @@ namespace {
return result;
}
[[nodiscard]] object_ptr<Ui::FlatLabel> MakeFeaturesBadge(
not_null<QWidget*> parent,
rpl::producer<QString> text) {
auto result = object_ptr<Ui::FlatLabel>(
parent,
std::move(text),
st::boostLevelBadge);
const auto label = result.data();
label->show();
label->paintRequest() | rpl::start_with_next([=] {
const auto size = label->textMaxWidth();
const auto rect = QRect(
(label->width() - size) / 2,
st::boostLevelBadge.margin.top(),
size,
st::boostLevelBadge.style.font->height
).marginsAdded(st::boostLevelBadge.margin);
auto p = QPainter(label);
auto gradient = QLinearGradient(
rect.topLeft(),
rect.topRight());
gradient.setStops(Ui::Premium::GiftGradientStops());
p.setBrush(gradient);
p.setPen(Qt::NoPen);
p.drawRoundedRect(rect, rect.height() / 2., rect.height() / 2.);
const auto &lineFg = st::windowBgRipple;
const auto line = st::boostLevelBadgeLine;
const auto top = st::boostLevelBadge.margin.top()
+ ((st::boostLevelBadge.style.font->height - line) / 2);
const auto left = 0;
const auto skip = st::boostLevelBadgeSkip;
if (const auto right = rect.x() - skip; right > left) {
p.fillRect(left, top, right - left, line, lineFg);
}
const auto right = label->width();
if (const auto left = rect.x() + rect.width() + skip
; left < right) {
p.fillRect(left, top, right - left, line, lineFg);
}
}, label->lifetime());
return result;
}
void AddFeaturesList(
not_null<Ui::VerticalLayout*> container,
const Ui::BoostFeatures &features,
int startFromLevel,
bool group) {
const auto add = [&](
rpl::producer<TextWithEntities> text,
const style::icon &st) {
const auto label = container->add(
object_ptr<Ui::FlatLabel>(
container,
std::move(text),
st::boostFeatureLabel),
st::boostFeaturePadding);
object_ptr<Info::Profile::FloatingIcon>(
label,
st,
st::boostFeatureIconPosition);
};
const auto proj = &Ui::Text::RichLangValue;
const auto max = std::max({
features.linkLogoLevel,
features.transcribeLevel,
features.emojiPackLevel,
features.emojiStatusLevel,
features.wallpaperLevel,
features.customWallpaperLevel,
(features.nameColorsByLevel.empty()
? 0
: features.nameColorsByLevel.back().first),
(features.linkStylesByLevel.empty()
? 0
: features.linkStylesByLevel.back().first),
});
auto nameColors = 0;
auto linkStyles = 0;
for (auto i = std::max(startFromLevel, 1); i <= max; ++i) {
const auto unlocks = (i == startFromLevel);
container->add(
MakeFeaturesBadge(
container,
(unlocks
? tr::lng_boost_level_unlocks
: tr::lng_boost_level)(
lt_count,
rpl::single(float64(i)))),
st::boostLevelBadgePadding);
add(
tr::lng_feature_stories(lt_count, rpl::single(float64(i)), proj),
st::boostFeatureStories);
if (!group) {
add(tr::lng_feature_reactions(
lt_count,
rpl::single(float64(i)),
proj
), st::boostFeatureCustomReactions);
if (const auto j = features.nameColorsByLevel.find(i)
; j != end(features.nameColorsByLevel)) {
nameColors += j->second;
}
if (nameColors > 0) {
add(tr::lng_feature_name_color_channel(
lt_count,
rpl::single(float64(nameColors)),
proj
), st::boostFeatureName);
}
if (const auto j = features.linkStylesByLevel.find(i)
; j != end(features.linkStylesByLevel)) {
linkStyles += j->second;
}
if (linkStyles > 0) {
add(tr::lng_feature_link_style_channel(
lt_count,
rpl::single(float64(linkStyles)),
proj
), st::boostFeatureLink);
}
if (i >= features.linkLogoLevel) {
add(
tr::lng_feature_link_emoji(proj),
st::boostFeatureCustomLink);
}
}
if (group && i >= features.emojiPackLevel) {
add(
tr::lng_feature_custom_emoji_pack(proj),
st::boostFeatureCustomEmoji);
}
if (group && i >= features.transcribeLevel) {
add(
tr::lng_feature_transcribe(proj),
st::boostFeatureTranscribe);
}
if (i >= features.emojiStatusLevel) {
add(
tr::lng_feature_emoji_status(proj),
st::boostFeatureEmojiStatus);
}
if (i >= features.wallpaperLevel) {
add(
(group
? tr::lng_feature_backgrounds_group
: tr::lng_feature_backgrounds_channel)(
lt_count,
rpl::single(float64(features.wallpapersCount)),
proj),
st::boostFeatureBackground);
}
if (i >= features.customWallpaperLevel) {
add(
(group
? tr::lng_feature_custom_background_group
: tr::lng_feature_custom_background_channel)(proj),
st::boostFeatureCustomBackground);
}
}
}
} // namespace
void StartFireworks(not_null<QWidget*> parent) {
@ -153,7 +323,10 @@ void BoostBox(
state->data.value(),
st::boxRowPadding);
box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
box->setMaxHeight(st::boostBoxMaxHeight);
const auto close = box->addTopButton(
st::boxTitleClose,
[=] { box->closeBox(); });
const auto name = data.name;
@ -192,21 +365,12 @@ void BoostBox(
Ui::Text::RichLangValue);
return (counters.mine || full)
? (left
? (!counters.level
? (data.group
? tr::lng_boost_channel_you_first_group
: tr::lng_boost_channel_you_first)(
lt_count,
rpl::single(float64(left)),
Ui::Text::RichLangValue)
: (data.group
? tr::lng_boost_channel_you_more_group
: tr::lng_boost_channel_you_more)(
lt_count,
rpl::single(float64(left)),
lt_post,
std::move(post),
Ui::Text::RichLangValue))
? tr::lng_boost_channel_needs_unlock(
lt_count,
rpl::single(float64(left)),
lt_channel,
rpl::single(bold),
Ui::Text::RichLangValue)
: (!counters.level
? (data.group
? tr::lng_boost_channel_reached_first_group
@ -220,23 +384,38 @@ void BoostBox(
lt_post,
std::move(post),
Ui::Text::RichLangValue)))
: !counters.level
? tr::lng_boost_channel_needs_first(
: tr::lng_boost_channel_needs_unlock(
lt_count,
rpl::single(float64(left)),
lt_channel,
rpl::single(bold),
Ui::Text::RichLangValue)
: tr::lng_boost_channel_needs_more(
lt_count,
rpl::single(float64(left)),
lt_channel,
rpl::single(bold),
lt_post,
std::move(post),
Ui::Text::RichLangValue);
}) | rpl::flatten_latest();
auto faded = object_ptr<Ui::FadeWrap<>>(
close->parentWidget(),
MakeTitle(
box,
rpl::duplicate(title),
rpl::duplicate(repeated),
false));
const auto titleInner = faded.data();
titleInner->move(st::boxTitlePosition);
titleInner->resizeToWidth(st::boxWideWidth
- st::boxTitleClose.width
- st::boxTitlePosition.x());
titleInner->hide(anim::type::instant);
crl::on_main(titleInner, [=] {
titleInner->raise();
titleInner->toggleOn(rpl::single(
rpl::empty
) | rpl::then(
box->scrolls()
) | rpl::map([=] {
return box->scrollTop() > 0;
}));
});
box->addRow(
MakeTitle(box, std::move(title), std::move(repeated)),
st::boxRowPadding + QMargins(0, st::boostTitleSkip, 0, 0));
@ -249,6 +428,14 @@ void BoostBox(
(st::boxRowPadding
+ QMargins(0, st::boostTextSkip, 0, st::boostBottomSkip)));
const auto current = state->data.current();
box->setTitle(rpl::single(QString()));
AddFeaturesList(
box->verticalLayout(),
data.features,
current.level + (current.nextLevelBoosts ? 1 : 0),
data.group);
const auto allowMulti = data.allowMulti;
auto submit = state->data.value(
) | rpl::map([=](BoostCounters counters) {
@ -579,7 +766,7 @@ void FillBoostLimit(
container->add(object_ptr<Ui::FixedHeightWidget>(container, skip));
};
addSkip(st::boostSkipTop);
//addSkip(st::boostSkipTop);
const auto ratio = [=](BoostCounters counters) {
const auto min = counters.thisLevelBoosts;

View file

@ -30,9 +30,22 @@ struct BoostCounters {
BoostCounters) = default;
};
struct BoostFeatures {
base::flat_map<int, int> nameColorsByLevel;
base::flat_map<int, int> linkStylesByLevel;
int linkLogoLevel = 0;
int transcribeLevel = 0;
int emojiPackLevel = 0;
int emojiStatusLevel = 0;
int wallpaperLevel = 0;
int wallpapersCount = 0;
int customWallpaperLevel = 0;
};
struct BoostBoxData {
QString name;
BoostCounters boost;
BoostFeatures features;
bool allowMulti = false;
bool group = false;
};

View file

@ -290,7 +290,7 @@ boostReassignText: FlatLabel(defaultFlatLabel) {
}
boostBottomSkip: 6px;
boostBox: Box(premiumPreviewDoubledLimitsBox) {
buttonPadding: margins(22px, 22px, 22px, 22px);
buttonPadding: margins(16px, 12px, 16px, 12px);
buttonHeight: 42px;
button: RoundButton(defaultActiveButton) {
height: 42px;
@ -337,3 +337,30 @@ showOrBox: Box(boostBox) {
buttonPadding: margins(28px, 16px, 28px, 27px);
button: showOrShowButton;
}
boostBoxMaxHeight: 512px;
boostLevelBadge: FlatLabel(defaultFlatLabel) {
margin: margins(12px, 4px, 12px, 4px);
style: semiboldTextStyle;
textFg: premiumButtonFg;
align: align(top);
}
boostLevelBadgePadding: margins(30px, 12px, 32px, 12px);
boostLevelBadgeSkip: 8px;
boostLevelBadgeLine: 1px;
boostFeatureLabel: FlatLabel(defaultFlatLabel) {
margin: margins(36px, 4px, 0px, 4px);
}
boostFeaturePadding: margins(64px, 6px, 24px, 6px);
boostFeatureIconPosition: point(0px, 0px);
boostFeatureBackground: icon{{ "settings/premium/features/background", windowBgActive }};
boostFeatureCustomBackground: icon{{ "settings/premium/features/custom_background", windowBgActive }};
boostFeatureCustomEmoji: icon{{ "settings/premium/features/custom_emoji", windowBgActive }};
boostFeatureCustomLink: icon{{ "settings/premium/features/custom_link", windowBgActive }};
boostFeatureCustomReactions: icon{{ "settings/premium/features/custom_reactions", windowBgActive }};
boostFeatureEmojiStatus: icon{{ "settings/premium/features/emoji_status", windowBgActive }};
boostFeatureLink: icon{{ "settings/premium/features/link", windowBgActive }};
boostFeatureName: icon{{ "settings/premium/features/name", windowBgActive }};
boostFeatureStories: icon{{ "settings/premium/features/stories", windowBgActive }};
boostFeatureTranscribe: icon{{ "settings/premium/features/transcribe", windowBgActive }};

View file

@ -630,6 +630,7 @@ void SessionNavigation::resolveBoostState(not_null<ChannelData*> channel) {
uiShow()->show(Box(Ui::BoostBox, Ui::BoostBoxData{
.name = channel->name(),
.boost = ParseBoostCounters(result),
.features = LookupBoostFeatures(channel),
.allowMulti = (BoostsForGift(_session) > 0),
.group = channel->isMegagroup(),
}, submit));