Show a new "Battery and Animations" settings item.

This commit is contained in:
John Preston 2023-02-25 16:17:48 +04:00
parent 588d5ad695
commit 388541a3fb
24 changed files with 220 additions and 116 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

View file

@ -608,7 +608,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_security_bots" = "Bots and websites"; "lng_settings_security_bots" = "Bots and websites";
"lng_settings_clear_payment_info" = "Clear Payment and Shipping Info"; "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" = "Animated Stickers";
"lng_settings_power_stickers_panel" = "Autoplay in panel"; "lng_settings_power_stickers_panel" = "Autoplay in panel";
"lng_settings_power_stickers_chat" = "Autoplay in chat"; "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_chat_spoiler" = "Animated spoiler effect";
"lng_settings_power_calls" = "Animations in Calls"; "lng_settings_power_calls" = "Animations in Calls";
"lng_settings_power_ui" = "Interface animations"; "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_on" = "On";
"lng_settings_cloud_password_off" = "Off"; "lng_settings_cloud_password_off" = "Off";

View file

@ -297,7 +297,7 @@ void EditAdminBox::prepare() {
& (filterByMyRights ? channel->adminRights() : ~Flag(0))); & (filterByMyRights ? channel->adminRights() : ~Flag(0)));
const auto disabledMessages = [&] { const auto disabledMessages = [&] {
auto result = std::map<Flags, QString>(); auto result = base::flat_map<Flags, QString>();
if (!canSave()) { if (!canSave()) {
result.emplace( result.emplace(
~Flags(0), ~Flags(0),
@ -725,7 +725,7 @@ void EditRestrictedBox::prepare() {
? (Flag::ChangeInfo | Flag::PinMessages) ? (Flag::ChangeInfo | Flag::PinMessages)
: Flags(0))); : Flags(0)));
const auto disabledMessages = [&] { const auto disabledMessages = [&] {
auto result = std::map<Flags, QString>(); auto result = base::flat_map<Flags, QString>();
if (!canSave()) { if (!canSave()) {
result.emplace( result.emplace(
~Flags(0), ~Flags(0),

View file

@ -48,18 +48,12 @@ constexpr auto kSuggestGigagroupThreshold = 199000;
return {}; return {};
} }
struct NestedRestrictionLabels {
std::optional<rpl::producer<QString>> nestedLabel;
std::vector<RestrictionLabel> restrictionLabels;
};
[[nodiscard]] auto NestedRestrictionLabelsList( [[nodiscard]] auto NestedRestrictionLabelsList(
Data::RestrictionsSetOptions options) { Data::RestrictionsSetOptions options) {
using Flag = ChatRestriction; using Flag = ChatRestriction;
auto first = std::vector<RestrictionLabel>{ auto first = std::vector<RestrictionLabel>{
{ Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) }, { 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>{ auto inner = std::vector<RestrictionLabel>{
{ Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) }, { Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) },
@ -89,7 +83,7 @@ struct NestedRestrictionLabels {
&RestrictionLabel::flags), &RestrictionLabel::flags),
end(second)); end(second));
} }
return std::vector<NestedRestrictionLabels>{ return std::vector<NestedEditFlagsLabels<ChatRestrictions>>{
{ std::nullopt, std::move(first) }, { std::nullopt, std::move(first) },
{ tr::lng_rights_chat_send_media(), std::move(inner) }, { tr::lng_rights_chat_send_media(), std::move(inner) },
{ std::nullopt, std::move(second) }, { std::nullopt, std::move(second) },
@ -267,19 +261,24 @@ ChatRestrictions DisabledByAdminRights(not_null<PeerData*> peer) {
not_null<Ui::RpWidget*> AddInnerToggle( not_null<Ui::RpWidget*> AddInnerToggle(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
const style::SettingsButton &st,
std::vector<not_null<Ui::AbstractCheckView*>> innerCheckViews, std::vector<not_null<Ui::AbstractCheckView*>> innerCheckViews,
not_null<Ui::SlideWrap<>*> wrap, not_null<Ui::SlideWrap<>*> wrap,
rpl::producer<QString> buttonLabel, rpl::producer<QString> buttonLabel,
std::optional<QString> locked) { std::optional<QString> locked,
const auto &stButton = st::rightsButton; Settings::IconDescriptor &&icon) {
const auto button = container->add(object_ptr<Ui::SettingsButton>( const auto button = container->add(object_ptr<Ui::SettingsButton>(
container, container,
nullptr, nullptr,
stButton)); st));
if (icon) {
Settings::AddButtonIcon(button, st, std::move(icon));
}
const auto toggleButton = Ui::CreateChild<Ui::SettingsButton>( const auto toggleButton = Ui::CreateChild<Ui::SettingsButton>(
container.get(), container.get(),
nullptr, nullptr,
stButton); st);
struct State final { struct State final {
State(const style::Toggle &st, Fn<void()> c) State(const style::Toggle &st, Fn<void()> c)
@ -291,7 +290,7 @@ not_null<Ui::RpWidget*> AddInnerToggle(
std::vector<not_null<Ui::AbstractCheckView*>> innerChecks; std::vector<not_null<Ui::AbstractCheckView*>> innerChecks;
}; };
const auto state = button->lifetime().make_state<State>( const auto state = button->lifetime().make_state<State>(
stButton.toggle, st.toggle,
[=] { toggleButton->update(); }); [=] { toggleButton->update(); });
state->innerChecks = std::move(innerCheckViews); state->innerChecks = std::move(innerCheckViews);
const auto countChecked = [=] { const auto countChecked = [=] {
@ -309,12 +308,12 @@ not_null<Ui::RpWidget*> AddInnerToggle(
{ {
const auto separator = Ui::CreateChild<Ui::RpWidget>(container.get()); const auto separator = Ui::CreateChild<Ui::RpWidget>(container.get());
separator->paintRequest( separator->paintRequest(
) | rpl::start_with_next([=, bg = stButton.textBgOver] { ) | rpl::start_with_next([=, bg = st.textBgOver] {
auto p = QPainter(separator); auto p = QPainter(separator);
p.fillRect(separator->rect(), bg); p.fillRect(separator->rect(), bg);
}, separator->lifetime()); }, separator->lifetime());
const auto separatorHeight = 2 * stButton.toggle.border const auto separatorHeight = 2 * st.toggle.border
+ stButton.toggle.diameter; + st.toggle.diameter;
button->geometryValue( button->geometryValue(
) | rpl::start_with_next([=](const QRect &r) { ) | rpl::start_with_next([=](const QRect &r) {
const auto w = st::rightsButtonToggleWidth; const auto w = st::rightsButtonToggleWidth;
@ -341,7 +340,7 @@ not_null<Ui::RpWidget*> AddInnerToggle(
toggleButton->sizeValue( toggleButton->sizeValue(
) | rpl::start_with_next([=](const QSize &s) { ) | rpl::start_with_next([=](const QSize &s) {
checkWidget->moveToRight( checkWidget->moveToRight(
stButton.toggleSkip, st.toggleSkip,
(s.height() - checkWidget->height()) / 2); (s.height() - checkWidget->height()) / 2);
}, toggleButton->lifetime()); }, toggleButton->lifetime());
} }
@ -392,8 +391,8 @@ not_null<Ui::RpWidget*> AddInnerToggle(
}, arrow->lifetime()); }, arrow->lifetime());
} }
button->sizeValue( button->sizeValue(
) | rpl::start_with_next([=](const QSize &s) { ) | rpl::start_with_next([=, &st](const QSize &s) {
const auto labelLeft = stButton.padding.left(); const auto labelLeft = st.padding.left();
const auto labelRight = s.width() - toggleButton->width(); const auto labelRight = s.width() - toggleButton->width();
label->resizeToWidth(labelRight - labelLeft - arrow->width()); label->resizeToWidth(labelRight - labelLeft - arrow->width());
@ -446,22 +445,18 @@ not_null<Ui::RpWidget*> AddInnerToggle(
return button; return button;
} }
template < template <typename Flags>
typename Flags, [[nodiscard]] EditFlagsControl<Flags> CreateEditFlags(
typename DisabledMessagePairs,
typename FlagLabelPairs>
[[nodiscard]] EditFlagsControl<Flags, Ui::RpWidget> CreateEditFlags(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> header,
Flags checked, Flags checked,
const DisabledMessagePairs &disabledMessagePairs, EditFlagsDescriptor<Flags> &&descriptor) {
const FlagLabelPairs &flagLabelPairsNested) {
struct State final { struct State final {
std::map<Flags, not_null<Ui::AbstractCheckView*>> checkViews; std::map<Flags, not_null<Ui::AbstractCheckView*>> checkViews;
rpl::event_stream<> anyChanges; rpl::event_stream<> anyChanges;
}; };
const auto state = container->lifetime().make_state<State>(); const auto state = container->lifetime().make_state<State>();
const auto &st = descriptor.st ? *descriptor.st : st::rightsButton;
const auto value = [=] { const auto value = [=] {
auto result = Flags(0); auto result = Flags(0);
for (const auto &[flags, checkView] : state->checkViews) { for (const auto &[flags, checkView] : state->checkViews) {
@ -478,23 +473,23 @@ template <
ApplyDependencies(state->checkViews, dependencies, view); ApplyDependencies(state->checkViews, dependencies, view);
}; };
if (header) { if (descriptor.header) {
container->add( container->add(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
container, container,
std::move(header), std::move(descriptor.header),
st::rightsHeaderLabel), st::rightsHeaderLabel),
st::rightsHeaderMargin); st::rightsHeaderMargin);
} }
const auto addCheckbox = [&]( const auto addCheckbox = [&](
not_null<Ui::VerticalLayout*> verticalLayout, not_null<Ui::VerticalLayout*> verticalLayout,
bool isInner, bool isInner,
Flags flags, const EditFlagsLabel<Flags> &entry) {
const QString &text) { const auto flags = entry.flags;
const auto lockedIt = ranges::find_if( const auto lockedIt = ranges::find_if(
disabledMessagePairs, descriptor.disabledMessages,
[&](const auto &pair) { return (pair.first & flags) != 0; }); [&](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::make_optional(lockedIt->second)
: std::nullopt; : std::nullopt;
const auto toggled = ((checked & flags) != 0); const auto toggled = ((checked & flags) != 0);
@ -504,10 +499,10 @@ template <
const auto checkbox = verticalLayout->add( const auto checkbox = verticalLayout->add(
object_ptr<Ui::Checkbox>( object_ptr<Ui::Checkbox>(
verticalLayout, verticalLayout,
text, entry.label,
toggled, toggled,
st::settingsCheckbox), st::settingsCheckbox),
st::rightsButton.padding); st.padding);
const auto button = Ui::CreateChild<Ui::RippleButton>( const auto button = Ui::CreateChild<Ui::RippleButton>(
verticalLayout.get(), verticalLayout.get(),
st::defaultRippleAnimation); st::defaultRippleAnimation);
@ -530,13 +525,14 @@ template <
} else { } else {
const auto button = Settings::AddButton( const auto button = Settings::AddButton(
verticalLayout, verticalLayout,
rpl::single(text), rpl::single(entry.label),
st::rightsButton); st,
{ entry.icon });
const auto toggle = Ui::CreateChild<Ui::RpWidget>( const auto toggle = Ui::CreateChild<Ui::RpWidget>(
button.get()); button.get());
auto &lifetime = toggle->lifetime(); auto &lifetime = toggle->lifetime();
const auto checkView = lifetime.make_state<Ui::ToggleView>( const auto checkView = lifetime.make_state<Ui::ToggleView>(
st::rightsButton.toggle, st.toggle,
toggled, toggled,
[=] { toggle->update(); }); [=] { toggle->update(); });
toggle->resize(checkView->getSize()); toggle->resize(checkView->getSize());
@ -548,7 +544,7 @@ template <
button->sizeValue( button->sizeValue(
) | rpl::start_with_next([=](const QSize &s) { ) | rpl::start_with_next([=](const QSize &s) {
toggle->moveToRight( toggle->moveToRight(
st::rightsButton.toggleSkip, st.toggleSkip,
(s.height() - toggle->height()) / 2); (s.height() - toggle->height()) / 2);
}, toggle->lifetime()); }, toggle->lifetime());
button->setClickedCallback([=] { button->setClickedCallback([=] {
@ -581,8 +577,10 @@ template <
return checkView; return checkView;
}; };
for (const auto &[nestedLabel, flagLabelPairs] : flagLabelPairsNested) { for (const auto &nestedWithLabel : descriptor.labels) {
const auto isInner = nestedLabel.has_value(); Assert(!nestedWithLabel.nested.empty());
const auto isInner = nestedWithLabel.nestingLabel.has_value();
auto wrap = isInner auto wrap = isInner
? object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( ? object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container, container,
@ -590,8 +588,8 @@ template <
: object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>{ nullptr }; : object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>{ nullptr };
const auto verticalLayout = wrap ? wrap->entity() : container.get(); const auto verticalLayout = wrap ? wrap->entity() : container.get();
auto innerChecks = std::vector<not_null<Ui::AbstractCheckView*>>(); auto innerChecks = std::vector<not_null<Ui::AbstractCheckView*>>();
for (const auto &[flags, label] : flagLabelPairs) { for (const auto &entry : nestedWithLabel.nested) {
const auto c = addCheckbox(verticalLayout, isInner, flags, label); const auto c = addCheckbox(verticalLayout, isInner, entry);
if (isInner) { if (isInner) {
innerChecks.push_back(c); innerChecks.push_back(c);
} }
@ -601,10 +599,12 @@ template <
raw->hide(anim::type::instant); raw->hide(anim::type::instant);
AddInnerToggle( AddInnerToggle(
container, container,
st,
innerChecks, innerChecks,
raw, raw,
*nestedLabel, *nestedWithLabel.nestingLabel,
std::nullopt); std::nullopt,
{ nestedWithLabel.nested.front().icon });
container->add(std::move(wrap)); container->add(std::move(wrap));
container->widthValue( container->widthValue(
) | rpl::start_with_next([=](int w) { ) | rpl::start_with_next([=](int w) {
@ -857,10 +857,10 @@ void ShowEditPeerPermissionsBox(
Unexpected("User in EditPeerPermissionsBox."); Unexpected("User in EditPeerPermissionsBox.");
}()); }());
const auto disabledMessages = [&] { const auto disabledMessages = [&] {
auto result = std::map<Flags, QString>(); auto result = base::flat_map<Flags, QString>();
result.emplace( result.emplace(
disabledByAdminRights, disabledByAdminRights,
tr::lng_rights_permission_cant_edit(tr::now)); tr::lng_rights_permission_cant_edit(tr::now));
if (const auto channel = peer->asChannel()) { if (const auto channel = peer->asChannel()) {
if (channel->isPublic() if (channel->isPublic()
|| (channel->isMegagroup() && channel->linkedChat())) { || (channel->isMegagroup() && channel->linkedChat())) {
@ -1026,19 +1026,21 @@ std::vector<AdminRightLabel> AdminRightLabels(
} }
} }
EditFlagsControl<ChatRestrictions, Ui::RpWidget> CreateEditRestrictions( EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
QWidget *parent, QWidget *parent,
rpl::producer<QString> header, rpl::producer<QString> header,
ChatRestrictions restrictions, ChatRestrictions restrictions,
std::map<ChatRestrictions, QString> disabledMessages, base::flat_map<ChatRestrictions, QString> disabledMessages,
Data::RestrictionsSetOptions options) { Data::RestrictionsSetOptions options) {
auto widget = object_ptr<Ui::VerticalLayout>(parent); auto widget = object_ptr<Ui::VerticalLayout>(parent);
auto result = CreateEditFlags( auto result = CreateEditFlags(
widget.data(), widget.data(),
header,
NegateRestrictions(restrictions), NegateRestrictions(restrictions),
disabledMessages, {
NestedRestrictionLabelsList(options)); .header = std::move(header),
.labels = NestedRestrictionLabelsList(options),
.disabledMessages = std::move(disabledMessages),
});
result.widget = std::move(widget); result.widget = std::move(widget);
result.value = [original = std::move(result.value)]{ result.value = [original = std::move(result.value)]{
return NegateRestrictions(original()); return NegateRestrictions(original());
@ -1050,22 +1052,21 @@ EditFlagsControl<ChatRestrictions, Ui::RpWidget> CreateEditRestrictions(
return result; return result;
} }
EditFlagsControl<ChatAdminRights, Ui::RpWidget> CreateEditAdminRights( EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
QWidget *parent, QWidget *parent,
rpl::producer<QString> header, rpl::producer<QString> header,
ChatAdminRights rights, ChatAdminRights rights,
std::map<ChatAdminRights, QString> disabledMessages, base::flat_map<ChatAdminRights, QString> disabledMessages,
Data::AdminRightsSetOptions options) { 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 widget = object_ptr<Ui::VerticalLayout>(parent);
auto result = CreateEditFlags( auto result = CreateEditFlags(
widget.data(), widget.data(),
header,
rights, 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); result.widget = std::move(widget);
return result; return result;
@ -1130,24 +1131,22 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
ChatAdminRights AdminRightsForOwnershipTransfer( ChatAdminRights AdminRightsForOwnershipTransfer(
Data::AdminRightsSetOptions options) { Data::AdminRightsSetOptions options) {
auto result = ChatAdminRights(); auto result = ChatAdminRights();
for (const auto &[flag, label] : AdminRightLabels(options)) { for (const auto &entry : AdminRightLabels(options)) {
if (!(flag & ChatAdminRight::Anonymous)) { if (!(entry.flags & ChatAdminRight::Anonymous)) {
result |= flag; result |= entry.flags;
} }
} }
return result; return result;
} }
EditFlagsControl<PowerSaving::Flags, Ui::RpWidget> CreateEditPowerSaving( EditFlagsControl<PowerSaving::Flags> CreateEditPowerSaving(
QWidget *parent, QWidget *parent,
PowerSaving::Flags flags) { PowerSaving::Flags flags) {
auto widget = object_ptr<Ui::VerticalLayout>(parent); auto widget = object_ptr<Ui::VerticalLayout>(parent);
auto result = CreateEditFlags( auto result = CreateEditFlags(
widget.data(), widget.data(),
nullptr,
flags, flags,
std::map<PowerSaving::Flags, QString>{}, Settings::PowerSavingLabels());
Settings::PowerSavingLabelsList());
result.widget = std::move(widget); result.widget = std::move(widget);
return result; return result;

View file

@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat_participant_status.h" #include "data/data_chat_participant_status.h"
namespace style {
struct SettingsButton;
} // namespace style
namespace Ui { namespace Ui {
class GenericBox; class GenericBox;
class RoundButton; class RoundButton;
@ -44,42 +48,57 @@ void ShowEditPeerPermissionsBox(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller);
struct RestrictionLabel { template <typename Flags>
ChatRestrictions flags; struct EditFlagsLabel {
Flags flags;
QString label; QString label;
const style::icon *icon = nullptr;
}; };
[[nodiscard]] std::vector<RestrictionLabel> RestrictionLabels(
Data::RestrictionsSetOptions options);
struct AdminRightLabel { template <typename Flags>
ChatAdminRights flags;
QString label;
};
[[nodiscard]] std::vector<AdminRightLabel> AdminRightLabels(
Data::AdminRightsSetOptions options);
template <typename Flags, typename Widget>
struct EditFlagsControl { struct EditFlagsControl {
object_ptr<Widget> widget; object_ptr<Ui::RpWidget> widget;
Fn<Flags()> value; Fn<Flags()> value;
rpl::producer<Flags> changes; 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( [[nodiscard]] auto CreateEditRestrictions(
QWidget *parent, QWidget *parent,
rpl::producer<QString> header, rpl::producer<QString> header,
ChatRestrictions restrictions, ChatRestrictions restrictions,
std::map<ChatRestrictions, QString> disabledMessages, base::flat_map<ChatRestrictions, QString> disabledMessages,
Data::RestrictionsSetOptions options) Data::RestrictionsSetOptions options)
-> EditFlagsControl<ChatRestrictions, Ui::RpWidget>; -> EditFlagsControl<ChatRestrictions>;
[[nodiscard]] auto CreateEditAdminRights( [[nodiscard]] auto CreateEditAdminRights(
QWidget *parent, QWidget *parent,
rpl::producer<QString> header, rpl::producer<QString> header,
ChatAdminRights rights, ChatAdminRights rights,
std::map<ChatAdminRights, QString> disabledMessages, base::flat_map<ChatAdminRights, QString> disabledMessages,
Data::AdminRightsSetOptions options) Data::AdminRightsSetOptions options)
-> EditFlagsControl<ChatAdminRights, Ui::RpWidget>; -> EditFlagsControl<ChatAdminRights>;
[[nodiscard]] ChatAdminRights DisabledByDefaultRestrictions( [[nodiscard]] ChatAdminRights DisabledByDefaultRestrictions(
not_null<PeerData*> peer); not_null<PeerData*> peer);
@ -91,4 +110,4 @@ struct EditFlagsControl {
[[nodiscard]] auto CreateEditPowerSaving( [[nodiscard]] auto CreateEditPowerSaving(
QWidget *parent, QWidget *parent,
PowerSaving::Flags flags PowerSaving::Flags flags
) -> EditFlagsControl<PowerSaving::Flags, Ui::RpWidget>; ) -> EditFlagsControl<PowerSaving::Flags>;

View file

@ -81,6 +81,7 @@ settingsIconFolders: icon {{ "settings/folders", settingsIconFg }};
settingsIconGeneral: icon {{ "settings/advanced", settingsIconFg }}; settingsIconGeneral: icon {{ "settings/advanced", settingsIconFg }};
settingsIconLock: icon {{ "settings/lock", settingsIconFg }}; settingsIconLock: icon {{ "settings/lock", settingsIconFg }};
settingsIconLanguage: icon {{ "settings/language", settingsIconFg }}; settingsIconLanguage: icon {{ "settings/language", settingsIconFg }};
settingsIconBattery: icon {{ "settings/battery", settingsIconFg }};
settingsIconInterfaceScale: icon {{ "settings/interface_scale", settingsIconFg }}; settingsIconInterfaceScale: icon {{ "settings/interface_scale", settingsIconFg }};
settingsIconFaq: icon {{ "settings/faq", settingsIconFg }}; settingsIconFaq: icon {{ "settings/faq", settingsIconFg }};
settingsIconCalls: icon {{ "settings/calls", settingsIconFg }}; settingsIconCalls: icon {{ "settings/calls", settingsIconFg }};
@ -526,3 +527,13 @@ requestPeerRestriction: FlatLabel(defaultFlatLabel) {
lineHeight: 22px; 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);

View file

@ -664,7 +664,7 @@ void SetupAnimations(
not_null<Ui::VerticalLayout*> container) { not_null<Ui::VerticalLayout*> container) {
AddButton( AddButton(
container, container,
tr::lng_settings_power_title(), tr::lng_settings_power_menu(),
st::settingsButtonNoIcon st::settingsButtonNoIcon
)->setClickedCallback([=] { )->setClickedCallback([=] {
window->show(Box(PowerSavingBox)); window->show(Box(PowerSavingBox));

View file

@ -60,11 +60,12 @@ base::options::toggle OptionMonoSettingsIcons({
const char kOptionMonoSettingsIcons[] = "mono-settings-icons"; const char kOptionMonoSettingsIcons[] = "mono-settings-icons";
Icon::Icon(IconDescriptor descriptor) : _icon(descriptor.icon) { Icon::Icon(IconDescriptor descriptor) : _icon(descriptor.icon) {
const auto background = [&] { const auto background = [&]() -> const style::color* {
if (OptionMonoSettingsIcons.value()) { if (descriptor.type == IconType::Simple) {
return nullptr;
} else if (OptionMonoSettingsIcons.value()) {
return &st::transparent; return &st::transparent;
} } else if (descriptor.color > 0) {
if (descriptor.color > 0) {
const auto list = std::array{ const auto list = std::array{
&st::settingsIconBg1, &st::settingsIconBg1,
&st::settingsIconBg2, &st::settingsIconBg2,

View file

@ -141,6 +141,7 @@ inline constexpr auto kIconGray = 9;
enum class IconType { enum class IconType {
Rounded, Rounded,
Round, Round,
Simple,
}; };
struct IconDescriptor { struct IconDescriptor {

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_advanced.h" #include "settings/settings_advanced.h"
#include "settings/settings_folders.h" #include "settings/settings_folders.h"
#include "settings/settings_calls.h" #include "settings/settings_calls.h"
#include "settings/settings_power_saving.h"
#include "settings/settings_premium.h" #include "settings/settings_premium.h"
#include "settings/settings_scale_preview.h" #include "settings/settings_scale_preview.h"
#include "boxes/language_box.h" #include "boxes/language_box.h"
@ -257,6 +258,19 @@ void Cover::refreshUsernameGeometry(int newWidth) {
} // namespace } // 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( void SetupLanguageButton(
not_null<Window::Controller*> window, not_null<Window::Controller*> window,
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
@ -270,7 +284,7 @@ void SetupLanguageButton(
Lang::GetInstance().idChanges() Lang::GetInstance().idChanges()
) | rpl::map([] { return Lang::GetInstance().nativeName(); }), ) | rpl::map([] { return Lang::GetInstance().nativeName(); }),
icon ? st::settingsButton : st::settingsButtonNoIcon, 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()); const auto guard = Ui::CreateChild<base::binary_guard>(button.get());
button->addClickHandler([=] { button->addClickHandler([=] {
const auto m = button->clickModifiers(); const auto m = button->clickModifiers();
@ -381,6 +395,7 @@ void SetupSections(
Calls::Id(), Calls::Id(),
{ &st::settingsIconCalls, kIconGreen }); { &st::settingsIconCalls, kIconGreen });
SetupPowerSavingButton(&controller->window(), container);
SetupLanguageButton(&controller->window(), container); SetupLanguageButton(&controller->window(), container);
if (controller->session().premiumPossible()) { if (controller->session().premiumPossible()) {

View file

@ -10,13 +10,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_permissions_box.h" #include "boxes/peers/edit_peer_permissions_box.h"
#include "core/application.h" #include "core/application.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "settings/settings_common.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/widgets/buttons.h"
#include "ui/power_saving.h" #include "ui/power_saving.h"
#include "styles/style_menu_icons.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
namespace Settings { namespace Settings {
void PowerSavingBox(not_null<Ui::GenericBox*> box) { void PowerSavingBox(not_null<Ui::GenericBox*> box) {
box->setStyle(st::layerBox);
box->setTitle(tr::lng_settings_power_title()); 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( auto [checkboxes, getResult, changes] = CreateEditPowerSaving(
box, box,
@ -24,6 +42,22 @@ void PowerSavingBox(not_null<Ui::GenericBox*> box) {
box->addRow(std::move(checkboxes), {}); 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] { box->addButton(tr::lng_settings_save(), [=, collect = getResult] {
Set(PowerSaving::kAll & ~collect()); Set(PowerSaving::kAll & ~collect());
Core::App().saveSettingsDelayed(); Core::App().saveSettingsDelayed();
@ -32,35 +66,56 @@ void PowerSavingBox(not_null<Ui::GenericBox*> box) {
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
} }
std::vector<NestedPowerSavingLabels> PowerSavingLabelsList() { EditFlagsDescriptor<PowerSaving::Flags> PowerSavingLabels() {
using namespace PowerSaving; using namespace PowerSaving;
using Label = PowerSavingLabel; using Label = EditFlagsLabel<Flags>;
auto stickers = std::vector<Label>{ 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) }, { kStickersChat, tr::lng_settings_power_stickers_chat(tr::now) },
}; };
auto emoji = std::vector<Label>{ 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) }, { kEmojiReactions, tr::lng_settings_power_emoji_reactions(tr::now) },
{ kEmojiChat, tr::lng_settings_power_emoji_chat(tr::now) }, { kEmojiChat, tr::lng_settings_power_emoji_chat(tr::now) },
}; };
auto chat = std::vector<Label>{ 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) }, { kChatSpoiler, tr::lng_settings_power_chat_spoiler(tr::now) },
}; };
auto calls = std::vector<Label>{ 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>{ 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_stickers(), std::move(stickers) },
{ tr::lng_settings_power_emoji(), std::move(emoji) }, { tr::lng_settings_power_emoji(), std::move(emoji) },
{ tr::lng_settings_power_chat(), std::move(chat) }, { tr::lng_settings_power_chat(), std::move(chat) },
{ std::nullopt, std::move(calls) }, { std::nullopt, std::move(calls) },
{ std::nullopt, std::move(animations) }, { std::nullopt, std::move(animations), },
}; }, .st = &st::powerSavingButton };
} }
} // namespace Settings } // namespace Settings

View file

@ -7,8 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/flags.h"
template <typename Flags>
struct EditFlagsDescriptor;
namespace PowerSaving { namespace PowerSaving {
enum Flag : uint32; enum Flag : uint32;
using Flags = base::flags<Flag>;
} // namespace PowerSaving } // namespace PowerSaving
namespace Ui { namespace Ui {
@ -19,16 +25,6 @@ namespace Settings {
void PowerSavingBox(not_null<Ui::GenericBox*> box); void PowerSavingBox(not_null<Ui::GenericBox*> box);
struct PowerSavingLabel { [[nodiscard]] EditFlagsDescriptor<PowerSaving::Flags> PowerSavingLabels();
PowerSaving::Flag flags;
QString label;
};
struct NestedPowerSavingLabels {
std::optional<rpl::producer<QString>> nestedLabel;
std::vector<PowerSavingLabel> restrictionLabels;
};
[[nodiscard]] std::vector<NestedPowerSavingLabels> PowerSavingLabelsList();
} // namespace PowerSaving } // namespace PowerSaving

View file

@ -20,6 +20,7 @@ menuIconDelete: icon {{ "menu/delete", menuIconColor }};
menuIconSelect: icon {{ "menu/select", menuIconColor }}; menuIconSelect: icon {{ "menu/select", menuIconColor }};
menuIconSaveImage: icon {{ "menu/save_image", menuIconColor }}; menuIconSaveImage: icon {{ "menu/save_image", menuIconColor }};
menuIconStickers: icon {{ "menu/stickers", menuIconColor }}; menuIconStickers: icon {{ "menu/stickers", menuIconColor }};
menuIconEmoji: icon {{ "menu/emoji", menuIconColor }};
menuIconCancel: icon {{ "menu/cancel", menuIconColor }}; menuIconCancel: icon {{ "menu/cancel", menuIconColor }};
menuIconShowInChat: icon {{ "menu/show_in_chat", menuIconColor }}; menuIconShowInChat: icon {{ "menu/show_in_chat", menuIconColor }};
menuIconGif: icon {{ "menu/gif", menuIconColor }}; menuIconGif: icon {{ "menu/gif", menuIconColor }};
@ -100,6 +101,8 @@ menuIconDisable: icon {{ "menu/disable", menuIconColor }};
menuIconPhotoSet: icon {{ "menu/photo_set", menuIconColor }}; menuIconPhotoSet: icon {{ "menu/photo_set", menuIconColor }};
menuIconPhotoSuggest: icon {{ "menu/photo_suggest", menuIconColor }}; menuIconPhotoSuggest: icon {{ "menu/photo_suggest", menuIconColor }};
menuIconNewWindow: icon {{ "menu/new_window", 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 }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }};
menuIconTTLAnyTextPosition: point(11px, 22px); menuIconTTLAnyTextPosition: point(11px, 22px);