diff --git a/Telegram/Resources/icons/menu/chat_bubble.png b/Telegram/Resources/icons/menu/chat_bubble.png new file mode 100644 index 000000000..a22bd585d Binary files /dev/null and b/Telegram/Resources/icons/menu/chat_bubble.png differ diff --git a/Telegram/Resources/icons/menu/chat_bubble@2x.png b/Telegram/Resources/icons/menu/chat_bubble@2x.png new file mode 100644 index 000000000..8da64703f Binary files /dev/null and b/Telegram/Resources/icons/menu/chat_bubble@2x.png differ diff --git a/Telegram/Resources/icons/menu/chat_bubble@3x.png b/Telegram/Resources/icons/menu/chat_bubble@3x.png new file mode 100644 index 000000000..5862e9228 Binary files /dev/null and b/Telegram/Resources/icons/menu/chat_bubble@3x.png differ diff --git a/Telegram/Resources/icons/menu/emoji.png b/Telegram/Resources/icons/menu/emoji.png new file mode 100644 index 000000000..0820c4c24 Binary files /dev/null and b/Telegram/Resources/icons/menu/emoji.png differ diff --git a/Telegram/Resources/icons/menu/emoji@2x.png b/Telegram/Resources/icons/menu/emoji@2x.png new file mode 100644 index 000000000..24ced3250 Binary files /dev/null and b/Telegram/Resources/icons/menu/emoji@2x.png differ diff --git a/Telegram/Resources/icons/menu/emoji@3x.png b/Telegram/Resources/icons/menu/emoji@3x.png new file mode 100644 index 000000000..d2251e543 Binary files /dev/null and b/Telegram/Resources/icons/menu/emoji@3x.png differ diff --git a/Telegram/Resources/icons/menu/phone.png b/Telegram/Resources/icons/menu/phone.png new file mode 100644 index 000000000..d059c8e9a Binary files /dev/null and b/Telegram/Resources/icons/menu/phone.png differ diff --git a/Telegram/Resources/icons/menu/phone@2x.png b/Telegram/Resources/icons/menu/phone@2x.png new file mode 100644 index 000000000..920fc33b4 Binary files /dev/null and b/Telegram/Resources/icons/menu/phone@2x.png differ diff --git a/Telegram/Resources/icons/menu/phone@3x.png b/Telegram/Resources/icons/menu/phone@3x.png new file mode 100644 index 000000000..853e7e11a Binary files /dev/null and b/Telegram/Resources/icons/menu/phone@3x.png differ diff --git a/Telegram/Resources/icons/settings/battery.png b/Telegram/Resources/icons/settings/battery.png new file mode 100644 index 000000000..4287599be Binary files /dev/null and b/Telegram/Resources/icons/settings/battery.png differ diff --git a/Telegram/Resources/icons/settings/battery@2x.png b/Telegram/Resources/icons/settings/battery@2x.png new file mode 100644 index 000000000..b45409949 Binary files /dev/null and b/Telegram/Resources/icons/settings/battery@2x.png differ diff --git a/Telegram/Resources/icons/settings/battery@3x.png b/Telegram/Resources/icons/settings/battery@3x.png new file mode 100644 index 000000000..2c1fe9a28 Binary files /dev/null and b/Telegram/Resources/icons/settings/battery@3x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index bcdd1e01c..4c8916d70 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -608,7 +608,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_security_bots" = "Bots and websites"; "lng_settings_clear_payment_info" = "Clear Payment and Shipping Info"; -"lng_settings_power_title" = "Power efficiency"; +"lng_settings_power_menu" = "Battery and animations"; +"lng_settings_power_title" = "Power Usage"; +"lng_settings_power_subtitle" = "Power saving options"; "lng_settings_power_stickers" = "Animated Stickers"; "lng_settings_power_stickers_panel" = "Autoplay in panel"; "lng_settings_power_stickers_chat" = "Autoplay in chat"; @@ -621,6 +623,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_power_chat_spoiler" = "Animated spoiler effect"; "lng_settings_power_calls" = "Animations in Calls"; "lng_settings_power_ui" = "Interface animations"; +"lng_settings_power_auto" = "Save Power on Low Battery"; +"lng_settings_power_auto_about" = "Automatically disable all animations when your laptop is in a battery saving mode."; "lng_settings_cloud_password_on" = "On"; "lng_settings_cloud_password_off" = "Off"; diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index fc1b949cb..7006606ce 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -297,7 +297,7 @@ void EditAdminBox::prepare() { & (filterByMyRights ? channel->adminRights() : ~Flag(0))); const auto disabledMessages = [&] { - auto result = std::map<Flags, QString>(); + auto result = base::flat_map<Flags, QString>(); if (!canSave()) { result.emplace( ~Flags(0), @@ -725,7 +725,7 @@ void EditRestrictedBox::prepare() { ? (Flag::ChangeInfo | Flag::PinMessages) : Flags(0))); const auto disabledMessages = [&] { - auto result = std::map<Flags, QString>(); + auto result = base::flat_map<Flags, QString>(); if (!canSave()) { result.emplace( ~Flags(0), diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp index 421d3eb12..a32758489 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp @@ -48,18 +48,12 @@ constexpr auto kSuggestGigagroupThreshold = 199000; return {}; } -struct NestedRestrictionLabels { - std::optional<rpl::producer<QString>> nestedLabel; - std::vector<RestrictionLabel> restrictionLabels; -}; - [[nodiscard]] auto NestedRestrictionLabelsList( Data::RestrictionsSetOptions options) { using Flag = ChatRestriction; auto first = std::vector<RestrictionLabel>{ { Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) }, - // { Flag::SendMedia, tr::lng_rights_chat_send_media(tr::now) }, }; auto inner = std::vector<RestrictionLabel>{ { Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) }, @@ -89,7 +83,7 @@ struct NestedRestrictionLabels { &RestrictionLabel::flags), end(second)); } - return std::vector<NestedRestrictionLabels>{ + return std::vector<NestedEditFlagsLabels<ChatRestrictions>>{ { std::nullopt, std::move(first) }, { tr::lng_rights_chat_send_media(), std::move(inner) }, { std::nullopt, std::move(second) }, @@ -267,19 +261,24 @@ ChatRestrictions DisabledByAdminRights(not_null<PeerData*> peer) { not_null<Ui::RpWidget*> AddInnerToggle( not_null<Ui::VerticalLayout*> container, + const style::SettingsButton &st, std::vector<not_null<Ui::AbstractCheckView*>> innerCheckViews, not_null<Ui::SlideWrap<>*> wrap, rpl::producer<QString> buttonLabel, - std::optional<QString> locked) { - const auto &stButton = st::rightsButton; + std::optional<QString> locked, + Settings::IconDescriptor &&icon) { const auto button = container->add(object_ptr<Ui::SettingsButton>( container, nullptr, - stButton)); + st)); + if (icon) { + Settings::AddButtonIcon(button, st, std::move(icon)); + } + const auto toggleButton = Ui::CreateChild<Ui::SettingsButton>( container.get(), nullptr, - stButton); + st); struct State final { State(const style::Toggle &st, Fn<void()> c) @@ -291,7 +290,7 @@ not_null<Ui::RpWidget*> AddInnerToggle( std::vector<not_null<Ui::AbstractCheckView*>> innerChecks; }; const auto state = button->lifetime().make_state<State>( - stButton.toggle, + st.toggle, [=] { toggleButton->update(); }); state->innerChecks = std::move(innerCheckViews); const auto countChecked = [=] { @@ -309,12 +308,12 @@ not_null<Ui::RpWidget*> AddInnerToggle( { const auto separator = Ui::CreateChild<Ui::RpWidget>(container.get()); separator->paintRequest( - ) | rpl::start_with_next([=, bg = stButton.textBgOver] { + ) | rpl::start_with_next([=, bg = st.textBgOver] { auto p = QPainter(separator); p.fillRect(separator->rect(), bg); }, separator->lifetime()); - const auto separatorHeight = 2 * stButton.toggle.border - + stButton.toggle.diameter; + const auto separatorHeight = 2 * st.toggle.border + + st.toggle.diameter; button->geometryValue( ) | rpl::start_with_next([=](const QRect &r) { const auto w = st::rightsButtonToggleWidth; @@ -341,7 +340,7 @@ not_null<Ui::RpWidget*> AddInnerToggle( toggleButton->sizeValue( ) | rpl::start_with_next([=](const QSize &s) { checkWidget->moveToRight( - stButton.toggleSkip, + st.toggleSkip, (s.height() - checkWidget->height()) / 2); }, toggleButton->lifetime()); } @@ -392,8 +391,8 @@ not_null<Ui::RpWidget*> AddInnerToggle( }, arrow->lifetime()); } button->sizeValue( - ) | rpl::start_with_next([=](const QSize &s) { - const auto labelLeft = stButton.padding.left(); + ) | rpl::start_with_next([=, &st](const QSize &s) { + const auto labelLeft = st.padding.left(); const auto labelRight = s.width() - toggleButton->width(); label->resizeToWidth(labelRight - labelLeft - arrow->width()); @@ -446,22 +445,18 @@ not_null<Ui::RpWidget*> AddInnerToggle( return button; } -template < - typename Flags, - typename DisabledMessagePairs, - typename FlagLabelPairs> -[[nodiscard]] EditFlagsControl<Flags, Ui::RpWidget> CreateEditFlags( +template <typename Flags> +[[nodiscard]] EditFlagsControl<Flags> CreateEditFlags( not_null<Ui::VerticalLayout*> container, - rpl::producer<QString> header, Flags checked, - const DisabledMessagePairs &disabledMessagePairs, - const FlagLabelPairs &flagLabelPairsNested) { + EditFlagsDescriptor<Flags> &&descriptor) { struct State final { std::map<Flags, not_null<Ui::AbstractCheckView*>> checkViews; rpl::event_stream<> anyChanges; }; const auto state = container->lifetime().make_state<State>(); + const auto &st = descriptor.st ? *descriptor.st : st::rightsButton; const auto value = [=] { auto result = Flags(0); for (const auto &[flags, checkView] : state->checkViews) { @@ -478,23 +473,23 @@ template < ApplyDependencies(state->checkViews, dependencies, view); }; - if (header) { + if (descriptor.header) { container->add( object_ptr<Ui::FlatLabel>( container, - std::move(header), + std::move(descriptor.header), st::rightsHeaderLabel), st::rightsHeaderMargin); } const auto addCheckbox = [&]( not_null<Ui::VerticalLayout*> verticalLayout, bool isInner, - Flags flags, - const QString &text) { + const EditFlagsLabel<Flags> &entry) { + const auto flags = entry.flags; const auto lockedIt = ranges::find_if( - disabledMessagePairs, + descriptor.disabledMessages, [&](const auto &pair) { return (pair.first & flags) != 0; }); - const auto locked = (lockedIt != end(disabledMessagePairs)) + const auto locked = (lockedIt != end(descriptor.disabledMessages)) ? std::make_optional(lockedIt->second) : std::nullopt; const auto toggled = ((checked & flags) != 0); @@ -504,10 +499,10 @@ template < const auto checkbox = verticalLayout->add( object_ptr<Ui::Checkbox>( verticalLayout, - text, + entry.label, toggled, st::settingsCheckbox), - st::rightsButton.padding); + st.padding); const auto button = Ui::CreateChild<Ui::RippleButton>( verticalLayout.get(), st::defaultRippleAnimation); @@ -530,13 +525,14 @@ template < } else { const auto button = Settings::AddButton( verticalLayout, - rpl::single(text), - st::rightsButton); + rpl::single(entry.label), + st, + { entry.icon }); const auto toggle = Ui::CreateChild<Ui::RpWidget>( button.get()); auto &lifetime = toggle->lifetime(); const auto checkView = lifetime.make_state<Ui::ToggleView>( - st::rightsButton.toggle, + st.toggle, toggled, [=] { toggle->update(); }); toggle->resize(checkView->getSize()); @@ -548,7 +544,7 @@ template < button->sizeValue( ) | rpl::start_with_next([=](const QSize &s) { toggle->moveToRight( - st::rightsButton.toggleSkip, + st.toggleSkip, (s.height() - toggle->height()) / 2); }, toggle->lifetime()); button->setClickedCallback([=] { @@ -581,8 +577,10 @@ template < return checkView; }; - for (const auto &[nestedLabel, flagLabelPairs] : flagLabelPairsNested) { - const auto isInner = nestedLabel.has_value(); + for (const auto &nestedWithLabel : descriptor.labels) { + Assert(!nestedWithLabel.nested.empty()); + + const auto isInner = nestedWithLabel.nestingLabel.has_value(); auto wrap = isInner ? object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( container, @@ -590,8 +588,8 @@ template < : object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>{ nullptr }; const auto verticalLayout = wrap ? wrap->entity() : container.get(); auto innerChecks = std::vector<not_null<Ui::AbstractCheckView*>>(); - for (const auto &[flags, label] : flagLabelPairs) { - const auto c = addCheckbox(verticalLayout, isInner, flags, label); + for (const auto &entry : nestedWithLabel.nested) { + const auto c = addCheckbox(verticalLayout, isInner, entry); if (isInner) { innerChecks.push_back(c); } @@ -601,10 +599,12 @@ template < raw->hide(anim::type::instant); AddInnerToggle( container, + st, innerChecks, raw, - *nestedLabel, - std::nullopt); + *nestedWithLabel.nestingLabel, + std::nullopt, + { nestedWithLabel.nested.front().icon }); container->add(std::move(wrap)); container->widthValue( ) | rpl::start_with_next([=](int w) { @@ -857,10 +857,10 @@ void ShowEditPeerPermissionsBox( Unexpected("User in EditPeerPermissionsBox."); }()); const auto disabledMessages = [&] { - auto result = std::map<Flags, QString>(); - result.emplace( - disabledByAdminRights, - tr::lng_rights_permission_cant_edit(tr::now)); + auto result = base::flat_map<Flags, QString>(); + result.emplace( + disabledByAdminRights, + tr::lng_rights_permission_cant_edit(tr::now)); if (const auto channel = peer->asChannel()) { if (channel->isPublic() || (channel->isMegagroup() && channel->linkedChat())) { @@ -1026,19 +1026,21 @@ std::vector<AdminRightLabel> AdminRightLabels( } } -EditFlagsControl<ChatRestrictions, Ui::RpWidget> CreateEditRestrictions( +EditFlagsControl<ChatRestrictions> CreateEditRestrictions( QWidget *parent, rpl::producer<QString> header, ChatRestrictions restrictions, - std::map<ChatRestrictions, QString> disabledMessages, + base::flat_map<ChatRestrictions, QString> disabledMessages, Data::RestrictionsSetOptions options) { auto widget = object_ptr<Ui::VerticalLayout>(parent); auto result = CreateEditFlags( widget.data(), - header, NegateRestrictions(restrictions), - disabledMessages, - NestedRestrictionLabelsList(options)); + { + .header = std::move(header), + .labels = NestedRestrictionLabelsList(options), + .disabledMessages = std::move(disabledMessages), + }); result.widget = std::move(widget); result.value = [original = std::move(result.value)]{ return NegateRestrictions(original()); @@ -1050,22 +1052,21 @@ EditFlagsControl<ChatRestrictions, Ui::RpWidget> CreateEditRestrictions( return result; } -EditFlagsControl<ChatAdminRights, Ui::RpWidget> CreateEditAdminRights( +EditFlagsControl<ChatAdminRights> CreateEditAdminRights( QWidget *parent, rpl::producer<QString> header, ChatAdminRights rights, - std::map<ChatAdminRights, QString> disabledMessages, + base::flat_map<ChatAdminRights, QString> disabledMessages, Data::AdminRightsSetOptions options) { - using String = std::optional<rpl::producer<QString>>; - using Labels = std::pair<String, std::vector<AdminRightLabel>>; - auto widget = object_ptr<Ui::VerticalLayout>(parent); auto result = CreateEditFlags( widget.data(), - header, rights, - disabledMessages, - std::vector<Labels>{ { std::nullopt, AdminRightLabels(options) } }); + { + .header = std::move(header), + .labels = { { std::nullopt, AdminRightLabels(options) } }, + .disabledMessages = std::move(disabledMessages), + }); result.widget = std::move(widget); return result; @@ -1130,24 +1131,22 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) { ChatAdminRights AdminRightsForOwnershipTransfer( Data::AdminRightsSetOptions options) { auto result = ChatAdminRights(); - for (const auto &[flag, label] : AdminRightLabels(options)) { - if (!(flag & ChatAdminRight::Anonymous)) { - result |= flag; + for (const auto &entry : AdminRightLabels(options)) { + if (!(entry.flags & ChatAdminRight::Anonymous)) { + result |= entry.flags; } } return result; } -EditFlagsControl<PowerSaving::Flags, Ui::RpWidget> CreateEditPowerSaving( +EditFlagsControl<PowerSaving::Flags> CreateEditPowerSaving( QWidget *parent, PowerSaving::Flags flags) { auto widget = object_ptr<Ui::VerticalLayout>(parent); auto result = CreateEditFlags( widget.data(), - nullptr, flags, - std::map<PowerSaving::Flags, QString>{}, - Settings::PowerSavingLabelsList()); + Settings::PowerSavingLabels()); result.widget = std::move(widget); return result; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h index 75d806dea..0cc1d0ed8 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h @@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat_participant_status.h" +namespace style { +struct SettingsButton; +} // namespace style + namespace Ui { class GenericBox; class RoundButton; @@ -44,42 +48,57 @@ void ShowEditPeerPermissionsBox( not_null<ChannelData*> channel, not_null<Window::SessionController*> controller); -struct RestrictionLabel { - ChatRestrictions flags; +template <typename Flags> +struct EditFlagsLabel { + Flags flags; QString label; + const style::icon *icon = nullptr; }; -[[nodiscard]] std::vector<RestrictionLabel> RestrictionLabels( - Data::RestrictionsSetOptions options); -struct AdminRightLabel { - ChatAdminRights flags; - QString label; -}; -[[nodiscard]] std::vector<AdminRightLabel> AdminRightLabels( - Data::AdminRightsSetOptions options); - -template <typename Flags, typename Widget> +template <typename Flags> struct EditFlagsControl { - object_ptr<Widget> widget; + object_ptr<Ui::RpWidget> widget; Fn<Flags()> value; rpl::producer<Flags> changes; }; +template <typename Flags> +struct NestedEditFlagsLabels { + std::optional<rpl::producer<QString>> nestingLabel; + std::vector<EditFlagsLabel<Flags>> nested; +}; + +template <typename Flags> +struct EditFlagsDescriptor { + rpl::producer<QString> header; + std::vector<NestedEditFlagsLabels<Flags>> labels; + base::flat_map<Flags, QString> disabledMessages; + const style::SettingsButton *st = nullptr; +}; + +using RestrictionLabel = EditFlagsLabel<ChatRestrictions>; +[[nodiscard]] std::vector<RestrictionLabel> RestrictionLabels( + Data::RestrictionsSetOptions options); + +using AdminRightLabel = EditFlagsLabel<ChatAdminRights>; +[[nodiscard]] std::vector<AdminRightLabel> AdminRightLabels( + Data::AdminRightsSetOptions options); + [[nodiscard]] auto CreateEditRestrictions( QWidget *parent, rpl::producer<QString> header, ChatRestrictions restrictions, - std::map<ChatRestrictions, QString> disabledMessages, + base::flat_map<ChatRestrictions, QString> disabledMessages, Data::RestrictionsSetOptions options) --> EditFlagsControl<ChatRestrictions, Ui::RpWidget>; +-> EditFlagsControl<ChatRestrictions>; [[nodiscard]] auto CreateEditAdminRights( QWidget *parent, rpl::producer<QString> header, ChatAdminRights rights, - std::map<ChatAdminRights, QString> disabledMessages, + base::flat_map<ChatAdminRights, QString> disabledMessages, Data::AdminRightsSetOptions options) --> EditFlagsControl<ChatAdminRights, Ui::RpWidget>; +-> EditFlagsControl<ChatAdminRights>; [[nodiscard]] ChatAdminRights DisabledByDefaultRestrictions( not_null<PeerData*> peer); @@ -91,4 +110,4 @@ struct EditFlagsControl { [[nodiscard]] auto CreateEditPowerSaving( QWidget *parent, PowerSaving::Flags flags -) -> EditFlagsControl<PowerSaving::Flags, Ui::RpWidget>; +) -> EditFlagsControl<PowerSaving::Flags>; diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 76b5b9dc6..e2a72af3b 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -81,6 +81,7 @@ settingsIconFolders: icon {{ "settings/folders", settingsIconFg }}; settingsIconGeneral: icon {{ "settings/advanced", settingsIconFg }}; settingsIconLock: icon {{ "settings/lock", settingsIconFg }}; settingsIconLanguage: icon {{ "settings/language", settingsIconFg }}; +settingsIconBattery: icon {{ "settings/battery", settingsIconFg }}; settingsIconInterfaceScale: icon {{ "settings/interface_scale", settingsIconFg }}; settingsIconFaq: icon {{ "settings/faq", settingsIconFg }}; settingsIconCalls: icon {{ "settings/calls", settingsIconFg }}; @@ -526,3 +527,13 @@ requestPeerRestriction: FlatLabel(defaultFlatLabel) { lineHeight: 22px; } } + +powerSavingButton: SettingsButton(settingsButton) { + style: boxTextStyle; + padding: margins(57px, 8px, 22px, 8px); + iconLeft: 20px; +} +powerSavingButtonNoIcon: SettingsButton(powerSavingButton) { + padding: margins(22px, 8px, 22px, 8px); +} +powerSavingSubtitlePadding: margins(0px, 4px, 0px, -2px); diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index 3fe1c256f..4c6ef2284 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -664,7 +664,7 @@ void SetupAnimations( not_null<Ui::VerticalLayout*> container) { AddButton( container, - tr::lng_settings_power_title(), + tr::lng_settings_power_menu(), st::settingsButtonNoIcon )->setClickedCallback([=] { window->show(Box(PowerSavingBox)); diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index 7bd0e0983..f2144d1cc 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -60,11 +60,12 @@ base::options::toggle OptionMonoSettingsIcons({ const char kOptionMonoSettingsIcons[] = "mono-settings-icons"; Icon::Icon(IconDescriptor descriptor) : _icon(descriptor.icon) { - const auto background = [&] { - if (OptionMonoSettingsIcons.value()) { + const auto background = [&]() -> const style::color* { + if (descriptor.type == IconType::Simple) { + return nullptr; + } else if (OptionMonoSettingsIcons.value()) { return &st::transparent; - } - if (descriptor.color > 0) { + } else if (descriptor.color > 0) { const auto list = std::array{ &st::settingsIconBg1, &st::settingsIconBg2, diff --git a/Telegram/SourceFiles/settings/settings_common.h b/Telegram/SourceFiles/settings/settings_common.h index e0dffe917..9ee703093 100644 --- a/Telegram/SourceFiles/settings/settings_common.h +++ b/Telegram/SourceFiles/settings/settings_common.h @@ -141,6 +141,7 @@ inline constexpr auto kIconGray = 9; enum class IconType { Rounded, Round, + Simple, }; struct IconDescriptor { diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index f12f2e81e..39fd8133d 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_advanced.h" #include "settings/settings_folders.h" #include "settings/settings_calls.h" +#include "settings/settings_power_saving.h" #include "settings/settings_premium.h" #include "settings/settings_scale_preview.h" #include "boxes/language_box.h" @@ -257,6 +258,19 @@ void Cover::refreshUsernameGeometry(int newWidth) { } // namespace +void SetupPowerSavingButton( + not_null<Window::Controller*> window, + not_null<Ui::VerticalLayout*> container) { + const auto button = AddButton( + container, + tr::lng_settings_power_menu(), + st::settingsButton, + { &st::settingsIconBattery, kIconDarkOrange }); + button->setClickedCallback([=] { + window->show(Box(PowerSavingBox)); + }); +} + void SetupLanguageButton( not_null<Window::Controller*> window, not_null<Ui::VerticalLayout*> container, @@ -270,7 +284,7 @@ void SetupLanguageButton( Lang::GetInstance().idChanges() ) | rpl::map([] { return Lang::GetInstance().nativeName(); }), icon ? st::settingsButton : st::settingsButtonNoIcon, - { icon ? &st::settingsIconLanguage : nullptr, kIconDarkOrange }); + { icon ? &st::settingsIconLanguage : nullptr, kIconLightBlue }); const auto guard = Ui::CreateChild<base::binary_guard>(button.get()); button->addClickHandler([=] { const auto m = button->clickModifiers(); @@ -381,6 +395,7 @@ void SetupSections( Calls::Id(), { &st::settingsIconCalls, kIconGreen }); + SetupPowerSavingButton(&controller->window(), container); SetupLanguageButton(&controller->window(), container); if (controller->session().premiumPossible()) { diff --git a/Telegram/SourceFiles/settings/settings_power_saving.cpp b/Telegram/SourceFiles/settings/settings_power_saving.cpp index 88cc2829e..bd75ebbf7 100644 --- a/Telegram/SourceFiles/settings/settings_power_saving.cpp +++ b/Telegram/SourceFiles/settings/settings_power_saving.cpp @@ -10,13 +10,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_permissions_box.h" #include "core/application.h" #include "lang/lang_keys.h" +#include "settings/settings_common.h" #include "ui/layers/generic_box.h" +#include "ui/widgets/buttons.h" #include "ui/power_saving.h" +#include "styles/style_menu_icons.h" +#include "styles/style_layers.h" +#include "styles/style_settings.h" namespace Settings { void PowerSavingBox(not_null<Ui::GenericBox*> box) { + box->setStyle(st::layerBox); box->setTitle(tr::lng_settings_power_title()); + box->setWidth(st::boxWideWidth); + + const auto container = box->verticalLayout(); + + // Force top shadow visibility. + box->setPinnedToTopContent( + object_ptr<Ui::FixedHeightWidget>(box, st::lineWidth)); + + AddSubsectionTitle( + container, + tr::lng_settings_power_subtitle(), + st::powerSavingSubtitlePadding); auto [checkboxes, getResult, changes] = CreateEditPowerSaving( box, @@ -24,6 +42,22 @@ void PowerSavingBox(not_null<Ui::GenericBox*> box) { box->addRow(std::move(checkboxes), {}); + auto automatic = (Ui::SettingsButton*)nullptr; + const auto hasBattery = true; + const auto automaticEnabled = true; + if (hasBattery) { + AddSkip(container); + AddDivider(container); + AddSkip(container); + AddButton( + container, + tr::lng_settings_power_auto(), + st::powerSavingButtonNoIcon + )->toggleOn(rpl::single(automaticEnabled)); + AddSkip(container); + AddDividerText(container, tr::lng_settings_power_auto_about()); + } + box->addButton(tr::lng_settings_save(), [=, collect = getResult] { Set(PowerSaving::kAll & ~collect()); Core::App().saveSettingsDelayed(); @@ -32,35 +66,56 @@ void PowerSavingBox(not_null<Ui::GenericBox*> box) { box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); } -std::vector<NestedPowerSavingLabels> PowerSavingLabelsList() { +EditFlagsDescriptor<PowerSaving::Flags> PowerSavingLabels() { using namespace PowerSaving; - using Label = PowerSavingLabel; + using Label = EditFlagsLabel<Flags>; + auto stickers = std::vector<Label>{ - { kStickersPanel, tr::lng_settings_power_stickers_panel(tr::now) }, + { + kStickersPanel, + tr::lng_settings_power_stickers_panel(tr::now), + &st::menuIconStickers, + }, { kStickersChat, tr::lng_settings_power_stickers_chat(tr::now) }, }; auto emoji = std::vector<Label>{ - { kEmojiPanel, tr::lng_settings_power_emoji_panel(tr::now) }, + { + kEmojiPanel, + tr::lng_settings_power_emoji_panel(tr::now), + &st::menuIconEmoji, + }, { kEmojiReactions, tr::lng_settings_power_emoji_reactions(tr::now) }, { kEmojiChat, tr::lng_settings_power_emoji_chat(tr::now) }, }; auto chat = std::vector<Label>{ - { kChatBackground, tr::lng_settings_power_chat_background(tr::now) }, + { + kChatBackground, + tr::lng_settings_power_chat_background(tr::now), + &st::menuIconChatBubble, + }, { kChatSpoiler, tr::lng_settings_power_chat_spoiler(tr::now) }, }; auto calls = std::vector<Label>{ - { kCalls, tr::lng_settings_power_calls(tr::now) }, + { + kCalls, + tr::lng_settings_power_calls(tr::now), + &st::menuIconPhone, + }, }; auto animations = std::vector<Label>{ - { kAnimations, tr::lng_settings_power_ui(tr::now) }, + { + kAnimations, + tr::lng_settings_power_ui(tr::now), + &st::menuIconStartStream, + }, }; - return { + return { .labels = { { tr::lng_settings_power_stickers(), std::move(stickers) }, { tr::lng_settings_power_emoji(), std::move(emoji) }, { tr::lng_settings_power_chat(), std::move(chat) }, { std::nullopt, std::move(calls) }, - { std::nullopt, std::move(animations) }, - }; + { std::nullopt, std::move(animations), }, + }, .st = &st::powerSavingButton }; } } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_power_saving.h b/Telegram/SourceFiles/settings/settings_power_saving.h index d29e78cde..22d559b56 100644 --- a/Telegram/SourceFiles/settings/settings_power_saving.h +++ b/Telegram/SourceFiles/settings/settings_power_saving.h @@ -7,8 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/flags.h" + +template <typename Flags> +struct EditFlagsDescriptor; + namespace PowerSaving { enum Flag : uint32; +using Flags = base::flags<Flag>; } // namespace PowerSaving namespace Ui { @@ -19,16 +25,6 @@ namespace Settings { void PowerSavingBox(not_null<Ui::GenericBox*> box); -struct PowerSavingLabel { - PowerSaving::Flag flags; - QString label; -}; - -struct NestedPowerSavingLabels { - std::optional<rpl::producer<QString>> nestedLabel; - std::vector<PowerSavingLabel> restrictionLabels; -}; - -[[nodiscard]] std::vector<NestedPowerSavingLabels> PowerSavingLabelsList(); +[[nodiscard]] EditFlagsDescriptor<PowerSaving::Flags> PowerSavingLabels(); } // namespace PowerSaving diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index 142cc47f0..cf78f2bdc 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -20,6 +20,7 @@ menuIconDelete: icon {{ "menu/delete", menuIconColor }}; menuIconSelect: icon {{ "menu/select", menuIconColor }}; menuIconSaveImage: icon {{ "menu/save_image", menuIconColor }}; menuIconStickers: icon {{ "menu/stickers", menuIconColor }}; +menuIconEmoji: icon {{ "menu/emoji", menuIconColor }}; menuIconCancel: icon {{ "menu/cancel", menuIconColor }}; menuIconShowInChat: icon {{ "menu/show_in_chat", menuIconColor }}; menuIconGif: icon {{ "menu/gif", menuIconColor }}; @@ -100,6 +101,8 @@ menuIconDisable: icon {{ "menu/disable", menuIconColor }}; menuIconPhotoSet: icon {{ "menu/photo_set", menuIconColor }}; menuIconPhotoSuggest: icon {{ "menu/photo_suggest", menuIconColor }}; menuIconNewWindow: icon {{ "menu/new_window", menuIconColor }}; +menuIconChatBubble: icon {{ "menu/chat_bubble", menuIconColor }}; +menuIconPhone: icon {{ "menu/phone", menuIconColor }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }}; menuIconTTLAnyTextPosition: point(11px, 22px);