Initial settings builder experiment.

This commit is contained in:
John Preston
2025-12-29 17:26:21 +04:00
parent 156942f8fb
commit 375a8cea12
7 changed files with 430 additions and 1 deletions
+4
View File
@@ -1567,6 +1567,10 @@ PRIVATE
settings/settings_local_passcode.h
settings/settings_main.cpp
settings/settings_main.h
settings/builder/settings_builder.cpp
settings/builder/settings_builder.h
settings/builder/settings_main_builder.cpp
settings/builder/settings_main_builder.h
settings/settings_notifications.cpp
settings/settings_notifications.h
settings/settings_notifications_type.cpp
@@ -0,0 +1,125 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "settings/builder/settings_builder.h"
#include "settings/settings_common.h"
#include "ui/vertical_list.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/vertical_layout.h"
#include "styles/style_settings.h"
namespace Settings::Builder {
namespace {
[[nodiscard]] QString ResolveTitle(rpl::producer<QString> title) {
auto result = QString();
auto lifetime = rpl::lifetime();
std::move(title).start(
[&](QString value) { result = std::move(value); },
[](auto&&) {},
[] {},
lifetime);
return result;
}
} // namespace
SectionBuilder::SectionBuilder(BuildContext context)
: _context(std::move(context)) {
}
Ui::RpWidget *SectionBuilder::addControl(ControlArgs &&args) {
return v::match(_context, [&](const WidgetContext &ctx) {
if (!args.factory) {
return static_cast<Ui::RpWidget*>(nullptr);
}
auto widget = args.factory(ctx.container);
const auto raw = widget.data();
ctx.container->add(std::move(widget), args.margin);
return raw;
}, [&](const SearchContext &ctx) {
if (!args.id.isEmpty()) {
ctx.entries->push_back({
.id = std::move(args.id),
.title = ResolveTitle(std::move(args.title)),
.keywords = std::move(args.keywords),
});
}
return static_cast<Ui::RpWidget*>(nullptr);
});
}
Ui::SettingsButton *SectionBuilder::addSettingsButton(ButtonArgs &&args) {
const auto &st = args.st ? *args.st : st::settingsButton;
const auto button = v::match(_context, [&](const WidgetContext &ctx) -> Ui::SettingsButton* {
if (args.label) {
return AddButtonWithLabel(
ctx.container,
rpl::duplicate(args.title),
std::move(args.label),
st,
std::move(args.icon));
} else {
return ctx.container->add(CreateButtonWithIcon(
ctx.container,
rpl::duplicate(args.title),
st,
std::move(args.icon)));
}
}, [&](const SearchContext &ctx) -> Ui::SettingsButton* {
if (!args.id.isEmpty()) {
ctx.entries->push_back({
.id = std::move(args.id),
.title = ResolveTitle(std::move(args.title)),
.keywords = std::move(args.keywords),
});
}
return nullptr;
});
if (button && args.onClick) {
button->addClickHandler(std::move(args.onClick));
}
return button;
}
Ui::SettingsButton *SectionBuilder::addLabeledButton(ButtonArgs &&args) {
return addSettingsButton(std::move(args));
}
Ui::SettingsButton *SectionBuilder::addSectionButton(SectionArgs &&args) {
const auto button = addSettingsButton({
.id = std::move(args.id),
.title = std::move(args.title),
.icon = std::move(args.icon),
.keywords = std::move(args.keywords),
});
if (button) {
const auto showOther = std::get<WidgetContext>(_context).showOther;
const auto target = args.targetSection;
button->addClickHandler([=] {
showOther(target);
});
}
return button;
}
void SectionBuilder::addDivider() {
v::match(_context, [&](const WidgetContext &ctx) {
Ui::AddDivider(ctx.container);
}, [](const SearchContext &) {
});
}
void SectionBuilder::addSkip() {
v::match(_context, [&](const WidgetContext &ctx) {
Ui::AddSkip(ctx.container);
}, [](const SearchContext &) {
});
}
} // namespace Settings::Builder
@@ -0,0 +1,91 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/object_ptr.h"
#include "settings/settings_common.h"
#include "settings/settings_type.h"
#include <variant>
namespace Ui {
class RpWidget;
class VerticalLayout;
class SettingsButton;
} // namespace Ui
namespace Window {
class SessionController;
} // namespace Window
namespace style {
struct SettingsButton;
} // namespace style
namespace Settings::Builder {
struct SearchEntry {
QString id;
QString title;
QStringList keywords;
};
struct WidgetContext {
not_null<Ui::VerticalLayout*> container;
not_null<Window::SessionController*> controller;
Fn<void(Type)> showOther;
};
struct SearchContext {
not_null<std::vector<SearchEntry>*> entries;
};
using BuildContext = std::variant<WidgetContext, SearchContext>;
class SectionBuilder {
public:
explicit SectionBuilder(BuildContext context);
struct ControlArgs {
Fn<object_ptr<Ui::RpWidget>(not_null<Ui::VerticalLayout*>)> factory;
QString id;
rpl::producer<QString> title;
QStringList keywords;
style::margins margin;
};
Ui::RpWidget *addControl(ControlArgs &&args);
struct ButtonArgs {
QString id;
rpl::producer<QString> title;
const style::SettingsButton *st = nullptr;
IconDescriptor icon;
rpl::producer<QString> label;
Fn<void()> onClick;
QStringList keywords;
};
Ui::SettingsButton *addSettingsButton(ButtonArgs &&args);
Ui::SettingsButton *addLabeledButton(ButtonArgs &&args);
struct SectionArgs {
QString id;
rpl::producer<QString> title;
Type targetSection;
IconDescriptor icon;
QStringList keywords;
};
Ui::SettingsButton *addSectionButton(SectionArgs &&args);
void addDivider();
void addSkip();
private:
BuildContext _context;
};
} // namespace Settings::Builder
@@ -0,0 +1,145 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "settings/builder/settings_main_builder.h"
#include "ui/layers/generic_box.h"
#include "settings/builder/settings_builder.h"
#include "settings/settings_advanced.h"
#include "settings/settings_calls.h"
#include "settings/settings_chat.h"
#include "settings/settings_folders.h"
#include "settings/settings_information.h"
#include "settings/settings_notifications.h"
#include "settings/settings_power_saving.h"
#include "settings/settings_privacy_security.h"
#include "boxes/language_box.h"
#include "lang/lang_instance.h"
#include "lang/lang_keys.h"
#include "window/window_controller.h"
#include "window/window_session_controller.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
namespace Settings::Builder {
namespace {
void BuildMainSectionContent(
SectionBuilder &builder,
Window::SessionController *controller) {
builder.addDivider();
builder.addSkip();
builder.addSectionButton({
.id = u"main/account"_q,
.title = tr::lng_settings_my_account(),
.targetSection = Information::Id(),
.icon = { &st::menuIconProfile },
.keywords = { u"profile"_q, u"edit"_q, u"information"_q },
});
builder.addSectionButton({
.id = u"main/notifications"_q,
.title = tr::lng_settings_section_notify(),
.targetSection = Notifications::Id(),
.icon = { &st::menuIconNotifications },
.keywords = { u"alerts"_q, u"sounds"_q, u"badge"_q },
});
builder.addSectionButton({
.id = u"main/privacy"_q,
.title = tr::lng_settings_section_privacy(),
.targetSection = PrivacySecurity::Id(),
.icon = { &st::menuIconLock },
.keywords = { u"security"_q, u"passcode"_q, u"password"_q, u"2fa"_q },
});
builder.addSectionButton({
.id = u"main/chat"_q,
.title = tr::lng_settings_section_chat_settings(),
.targetSection = Chat::Id(),
.icon = { &st::menuIconChatBubble },
.keywords = { u"themes"_q, u"appearance"_q, u"stickers"_q },
});
builder.addSectionButton({
.id = u"main/folders"_q,
.title = tr::lng_settings_section_filters(),
.targetSection = Folders::Id(),
.icon = { &st::menuIconShowInFolder },
.keywords = { u"filters"_q, u"tabs"_q },
});
builder.addSectionButton({
.id = u"main/advanced"_q,
.title = tr::lng_settings_advanced(),
.targetSection = Advanced::Id(),
.icon = { &st::menuIconManage },
.keywords = { u"performance"_q, u"proxy"_q, u"experimental"_q },
});
builder.addSectionButton({
.id = u"main/devices"_q,
.title = tr::lng_settings_section_devices(),
.targetSection = Calls::Id(),
.icon = { &st::menuIconUnmute },
.keywords = { u"sessions"_q, u"calls"_q },
});
const auto window = controller ? &controller->window() : nullptr;
builder.addSettingsButton({
.id = u"main/power"_q,
.title = tr::lng_settings_power_menu(),
.icon = { &st::menuIconPowerUsage },
.onClick = window
? [=] { window->show(Box(PowerSavingBox)); }
: Fn<void()>(nullptr),
.keywords = { u"battery"_q, u"animations"_q, u"power"_q, u"saving"_q },
});
builder.addLabeledButton({
.id = u"main/language"_q,
.title = tr::lng_settings_language(),
.icon = { &st::menuIconTranslate },
.label = rpl::single(
Lang::GetInstance().id()
) | rpl::then(
Lang::GetInstance().idChanges()
) | rpl::map([] { return Lang::GetInstance().nativeName(); }),
.onClick = controller
? [=] { LanguageBox::Show(controller); }
: Fn<void()>(nullptr),
.keywords = { u"translate"_q, u"localization"_q },
});
builder.addSkip();
}
} // namespace
void BuildMainSection(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
Fn<void(Type)> showOther) {
auto builder = SectionBuilder(WidgetContext{
.container = container,
.controller = controller,
.showOther = std::move(showOther),
});
BuildMainSectionContent(builder, controller);
}
std::vector<SearchEntry> BuildMainSectionForSearch() {
auto entries = std::vector<SearchEntry>();
auto builder = SectionBuilder(SearchContext{
.entries = &entries,
});
BuildMainSectionContent(builder, nullptr);
return entries;
}
} // namespace Settings::Builder
@@ -0,0 +1,33 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "settings/settings_type.h"
#include <vector>
namespace Ui {
class VerticalLayout;
} // namespace Ui
namespace Window {
class SessionController;
} // namespace Window
namespace Settings::Builder {
struct SearchEntry;
void BuildMainSection(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
Fn<void(Type)> showOther);
[[nodiscard]] std::vector<SearchEntry> BuildMainSectionForSearch();
} // namespace Settings::Builder
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "settings/settings_main.h"
#include "settings/builder/settings_main_builder.h"
#include "api/api_credits.h"
#include "core/application.h"
#include "core/click_handler_types.h"
@@ -1034,7 +1035,7 @@ Main::Main(
not_null<Window::SessionController*> controller)
: Section(parent)
, _controller(controller) {
setupContent(controller);
setupContentWithBuilder(controller);
_controller->session().api().premium().reload();
}
@@ -1099,6 +1100,35 @@ void Main::setupContent(not_null<Window::SessionController*> controller) {
controller->session().data().cloudThemes().refresh();
}
void Main::setupContentWithBuilder(
not_null<Window::SessionController*> controller) {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
content->add(object_ptr<Cover>(
content,
controller,
controller->session().user()));
Builder::BuildMainSection(content, controller, showOtherMethod());
if (HasInterfaceScale()) {
Ui::AddDivider(content);
Ui::AddSkip(content);
SetupInterfaceScale(&controller->window(), content);
Ui::AddSkip(content);
}
SetupPremium(controller, content, showOtherMethod());
SetupHelp(controller, content);
Ui::ResizeFitChild(this, content);
controller->session().api().cloudPassword().reload();
controller->session().api().reloadContactSignupSilent();
controller->session().api().sensitiveContent().reload();
controller->session().api().globalPrivacy().reload();
controller->session().data().cloudThemes().refresh();
}
void OpenFaq(base::weak_ptr<Window::SessionController> weak) {
UrlClickHandler::Open(
tr::lng_settings_faq_link(tr::now),
@@ -45,6 +45,7 @@ protected:
private:
void setupContent(not_null<Window::SessionController*> controller);
void setupContentWithBuilder(not_null<Window::SessionController*> controller);
const not_null<Window::SessionController*> _controller;