Boost community features list.
After Width: | Height: | Size: 734 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 771 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 914 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 712 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 668 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 723 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram/Resources/icons/settings/premium/features/link.png
Normal file
After Width: | Height: | Size: 639 B |
BIN
Telegram/Resources/icons/settings/premium/features/link@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/settings/premium/features/link@3x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
Telegram/Resources/icons/settings/premium/features/name.png
Normal file
After Width: | Height: | Size: 841 B |
BIN
Telegram/Resources/icons/settings/premium/features/name@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/settings/premium/features/name@3x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
Telegram/Resources/icons/settings/premium/features/stories.png
Normal file
After Width: | Height: | Size: 806 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 705 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.3 KiB |
|
@ -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.";
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 }};
|
||||
|
|
|
@ -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));
|
||||
|
|