diff --git a/Telegram/Resources/icons/settings/premium/features/background.png b/Telegram/Resources/icons/settings/premium/features/background.png new file mode 100644 index 000000000..72d93ef9c Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/background.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/background@2x.png b/Telegram/Resources/icons/settings/premium/features/background@2x.png new file mode 100644 index 000000000..c2b1609ea Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/background@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/background@3x.png b/Telegram/Resources/icons/settings/premium/features/background@3x.png new file mode 100644 index 000000000..4eeae2a99 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/background@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_background.png b/Telegram/Resources/icons/settings/premium/features/custom_background.png new file mode 100644 index 000000000..7444c8516 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_background.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_background@2x.png b/Telegram/Resources/icons/settings/premium/features/custom_background@2x.png new file mode 100644 index 000000000..dc5afaf31 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_background@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_background@3x.png b/Telegram/Resources/icons/settings/premium/features/custom_background@3x.png new file mode 100644 index 000000000..dd6a63388 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_background@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_emoji.png b/Telegram/Resources/icons/settings/premium/features/custom_emoji.png new file mode 100644 index 000000000..9a9df92e1 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_emoji.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_emoji@2x.png b/Telegram/Resources/icons/settings/premium/features/custom_emoji@2x.png new file mode 100644 index 000000000..0a9fe460b Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_emoji@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_emoji@3x.png b/Telegram/Resources/icons/settings/premium/features/custom_emoji@3x.png new file mode 100644 index 000000000..42d4d3ff1 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_emoji@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_link.png b/Telegram/Resources/icons/settings/premium/features/custom_link.png new file mode 100644 index 000000000..7faddf706 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_link.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_link@2x.png b/Telegram/Resources/icons/settings/premium/features/custom_link@2x.png new file mode 100644 index 000000000..2b4f3daaf Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_link@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_link@3x.png b/Telegram/Resources/icons/settings/premium/features/custom_link@3x.png new file mode 100644 index 000000000..72bb62cf9 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_link@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_reactions.png b/Telegram/Resources/icons/settings/premium/features/custom_reactions.png new file mode 100644 index 000000000..b55137745 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_reactions.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_reactions@2x.png b/Telegram/Resources/icons/settings/premium/features/custom_reactions@2x.png new file mode 100644 index 000000000..d02916569 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_reactions@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/custom_reactions@3x.png b/Telegram/Resources/icons/settings/premium/features/custom_reactions@3x.png new file mode 100644 index 000000000..bd30a9274 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/custom_reactions@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/emoji_status.png b/Telegram/Resources/icons/settings/premium/features/emoji_status.png new file mode 100644 index 000000000..66e442ccf Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/emoji_status.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/emoji_status@2x.png b/Telegram/Resources/icons/settings/premium/features/emoji_status@2x.png new file mode 100644 index 000000000..7fc36e739 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/emoji_status@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/emoji_status@3x.png b/Telegram/Resources/icons/settings/premium/features/emoji_status@3x.png new file mode 100644 index 000000000..5e473fd02 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/emoji_status@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/link.png b/Telegram/Resources/icons/settings/premium/features/link.png new file mode 100644 index 000000000..a0c74beac Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/link.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/link@2x.png b/Telegram/Resources/icons/settings/premium/features/link@2x.png new file mode 100644 index 000000000..eae510a3a Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/link@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/link@3x.png b/Telegram/Resources/icons/settings/premium/features/link@3x.png new file mode 100644 index 000000000..8a01eeeae Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/link@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/name.png b/Telegram/Resources/icons/settings/premium/features/name.png new file mode 100644 index 000000000..e1199a3c1 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/name.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/name@2x.png b/Telegram/Resources/icons/settings/premium/features/name@2x.png new file mode 100644 index 000000000..ae11c588b Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/name@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/name@3x.png b/Telegram/Resources/icons/settings/premium/features/name@3x.png new file mode 100644 index 000000000..b5d88b1fa Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/name@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/stories.png b/Telegram/Resources/icons/settings/premium/features/stories.png new file mode 100644 index 000000000..bac1e2e14 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/stories.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/stories@2x.png b/Telegram/Resources/icons/settings/premium/features/stories@2x.png new file mode 100644 index 000000000..d077b1348 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/stories@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/stories@3x.png b/Telegram/Resources/icons/settings/premium/features/stories@3x.png new file mode 100644 index 000000000..71be3f645 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/stories@3x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/transcribe.png b/Telegram/Resources/icons/settings/premium/features/transcribe.png new file mode 100644 index 000000000..cf739e56b Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/transcribe.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/transcribe@2x.png b/Telegram/Resources/icons/settings/premium/features/transcribe@2x.png new file mode 100644 index 000000000..75bbedc24 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/transcribe@2x.png differ diff --git a/Telegram/Resources/icons/settings/premium/features/transcribe@3x.png b/Telegram/Resources/icons/settings/premium/features/transcribe@3x.png new file mode 100644 index 000000000..b2c516641 Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/features/transcribe@3x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index aa05e9541..655a29f76 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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."; diff --git a/Telegram/SourceFiles/api/api_peer_colors.cpp b/Telegram/SourceFiles/api/api_peer_colors.cpp index 50c2382fd..5f3fe12d2 100644 --- a/Telegram/SourceFiles/api/api_peer_colors.cpp +++ b/Telegram/SourceFiles/api/api_peer_colors.cpp @@ -55,19 +55,42 @@ rpl::producer> PeerColors::suggestedValue() const { auto PeerColors::indicesValue() const -> rpl::producer { - 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 &PeerColors::requiredLevelsGroup() const { + return _requiredLevelsGroup; +} + +const base::flat_map &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); diff --git a/Telegram/SourceFiles/api/api_peer_colors.h b/Telegram/SourceFiles/api/api_peer_colors.h index 0ad1a63c7..f8d379020 100644 --- a/Telegram/SourceFiles/api/api_peer_colors.h +++ b/Telegram/SourceFiles/api/api_peer_colors.h @@ -25,10 +25,19 @@ public: [[nodiscard]] std::vector suggested() const; [[nodiscard]] rpl::producer> suggestedValue() const; + [[nodiscard]] Ui::ColorIndicesCompressed indicesCurrent() const; [[nodiscard]] auto indicesValue() const -> rpl::producer; - [[nodiscard]] int requiredLevelFor( + [[nodiscard]] auto requiredLevelsGroup() const + -> const base::flat_map &; + [[nodiscard]] auto requiredLevelsChannel() const + -> const base::flat_map &; + + [[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> _suggested; - base::flat_map _requiredLevels; + base::flat_map _requiredLevelsGroup; + base::flat_map _requiredLevelsChannel; rpl::event_stream<> _colorIndicesChanged; std::unique_ptr _colorIndicesCurrent; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp index 38f064cb2..15e30cba2 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp @@ -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( "channel_bg_icon_level_min", diff --git a/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp b/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp index 178945d32..494996dbb 100644 --- a/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp @@ -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 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(key, fallback) : 0; + }; + + auto nameColorsByLevel = base::flat_map(); + auto linkStylesByLevel = base::flat_map(); + 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 session) { const auto key = u"boosts_per_sent_gift"_q; return session->account().appConfig().get(key, 0); diff --git a/Telegram/SourceFiles/boxes/peers/replace_boost_box.h b/Telegram/SourceFiles/boxes/peers/replace_boost_box.h index f15cf0b14..74ab7e093 100644 --- a/Telegram/SourceFiles/boxes/peers/replace_boost_box.h +++ b/Telegram/SourceFiles/boxes/peers/replace_boost_box.h @@ -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 channel); + [[nodiscard]] int BoostsForGift(not_null session); object_ptr ReassignBoostsBox( diff --git a/Telegram/SourceFiles/ui/boxes/boost_box.cpp b/Telegram/SourceFiles/ui/boxes/boost_box.cpp index dc47020a2..fc374dc30 100644 --- a/Telegram/SourceFiles/ui/boxes/boost_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/boost_box.cpp @@ -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 MakeTitle( - not_null box, + not_null parent, rpl::producer title, - rpl::producer repeated) { - auto result = object_ptr(box); + rpl::producer repeated, + bool centered = true) { + auto result = object_ptr(parent); struct State { not_null title; @@ -57,7 +60,7 @@ namespace { const auto notEmpty = [](const QString &text) { return !text.isEmpty(); }; - const auto state = box->lifetime().make_state(State{ + const auto state = parent->lifetime().make_state(State{ .title = Ui::CreateChild( 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 MakeFeaturesBadge( + not_null parent, + rpl::producer text) { + auto result = object_ptr( + 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 container, + const Ui::BoostFeatures &features, + int startFromLevel, + bool group) { + const auto add = [&]( + rpl::producer text, + const style::icon &st) { + const auto label = container->add( + object_ptr( + container, + std::move(text), + st::boostFeatureLabel), + st::boostFeaturePadding); + object_ptr( + 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 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>( + 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(container, skip)); }; - addSkip(st::boostSkipTop); + //addSkip(st::boostSkipTop); const auto ratio = [=](BoostCounters counters) { const auto min = counters.thisLevelBoosts; diff --git a/Telegram/SourceFiles/ui/boxes/boost_box.h b/Telegram/SourceFiles/ui/boxes/boost_box.h index 9acc046f7..064e697ef 100644 --- a/Telegram/SourceFiles/ui/boxes/boost_box.h +++ b/Telegram/SourceFiles/ui/boxes/boost_box.h @@ -30,9 +30,22 @@ struct BoostCounters { BoostCounters) = default; }; +struct BoostFeatures { + base::flat_map nameColorsByLevel; + base::flat_map 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; }; diff --git a/Telegram/SourceFiles/ui/effects/premium.style b/Telegram/SourceFiles/ui/effects/premium.style index 4134c5be9..5cce045bd 100644 --- a/Telegram/SourceFiles/ui/effects/premium.style +++ b/Telegram/SourceFiles/ui/effects/premium.style @@ -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 }}; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 258da20c6..8b099aa15 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -630,6 +630,7 @@ void SessionNavigation::resolveBoostState(not_null 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));