Upgrade settings_information to full builder pattern

- Move Information class to anonymous namespace in .cpp
- Export only Type InformationId() from header
- Keep exported helpers: SetupAccounts, UpdatePhotoLocally, Badge::*
- Use custom buildMethod with HighlightRegistry for all profile widgets
- Update all references to use InformationId() instead of Information::Id()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
John Preston
2026-01-14 19:24:02 +04:00
parent 4199bba706
commit 7e5b85c4b3
8 changed files with 148 additions and 79 deletions
@@ -326,7 +326,7 @@ void RegisterSettingsHandlers(Router &router) {
router.add(u"settings"_q, {
.path = u"edit"_q,
.action = SettingsSection{ ::Settings::Information::Id() },
.action = SettingsSection{ ::Settings::InformationId() },
});
router.add(u"settings"_q, {
@@ -336,7 +336,7 @@ void RegisterSettingsHandlers(Router &router) {
router.add(u"settings"_q, {
.path = u"my-profile/edit"_q,
.action = SettingsSection{ ::Settings::Information::Id() },
.action = SettingsSection{ ::Settings::InformationId() },
});
router.add(u"settings"_q, {
@@ -1719,7 +1719,7 @@ void RegisterSettingsHandlers(Router &router) {
router.add(u"settings"_q, {
.path = u"edit/bio"_q,
.action = SettingsControl{
::Settings::Information::Id(),
::Settings::InformationId(),
u"edit/bio"_q,
},
});
@@ -1753,14 +1753,14 @@ void RegisterSettingsHandlers(Router &router) {
router.add(u"settings"_q, {
.path = u"edit/channel"_q,
.action = SettingsControl{
::Settings::Information::Id(),
::Settings::InformationId(),
u"edit/channel"_q,
},
});
router.add(u"settings"_q, {
.path = u"edit/add-account"_q,
.action = SettingsControl{
::Settings::Information::Id(),
::Settings::InformationId(),
u"edit/add-account"_q,
},
});
@@ -837,7 +837,7 @@ bool ResolveSettings(
} else if (section == u"auto_delete"_q) {
return ::Settings::GlobalTTLId();
} else if (section == u"information"_q) {
return ::Settings::Information::Id();
return ::Settings::InformationId();
} else if (section == u"login_email"_q) {
ShowLoginEmailSettings(controller);
return {};
@@ -420,7 +420,7 @@ void WrapWidget::setupTopBarMenuToggle() {
button->addClickHandler([=] {
_controller->showSettings(::Settings::Search::Id());
});
} else if (section.settingsType() == ::Settings::Information::Id()) {
} else if (section.settingsType() == ::Settings::InformationId()) {
const auto controller = _controller->parentController();
const auto self = controller->session().user();
if (!self->username().isEmpty()) {
@@ -444,7 +444,7 @@ void WrapWidget::setupTopBarMenuToggle() {
const auto button = _topBar->addButton(
base::make_unique_q<Ui::IconButton>(_topBar, st));
button->addClickHandler([=] {
_controller->showSettings(::Settings::Information::Id());
_controller->showSettings(::Settings::InformationId());
});
} else if (section.type() == Section::Type::Downloads) {
auto &manager = Core::App().downloadManager();
@@ -1921,7 +1921,7 @@ void TopBar::addTopBarEditButton(
: st::infoTopBarBlackEdit)));
_topBarButton->show();
_topBarButton->addClickHandler([=] {
controller->showSettings(::Settings::Information::Id());
controller->showSettings(::Settings::InformationId());
});
widthValue() | rpl::on_next([=] {
@@ -203,7 +203,7 @@ const Ui::RoundRect *Widget::bottomSkipRounding() const {
rpl::producer<bool> Widget::desiredShadowVisibility() const {
return (_type == ::Settings::Main::Id()
|| _type == ::Settings::Information::Id())
|| _type == ::Settings::InformationId())
? ContentWidget::desiredShadowVisibility()
: rpl::single(true);
}
@@ -70,6 +70,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QBuffer>
namespace Settings {
namespace {
using namespace Builder;
@@ -82,8 +83,6 @@ struct InformationHighlightTargets {
QPointer<Ui::RpWidget> addAccount;
};
namespace {
constexpr auto kSaveBioTimeout = 1000;
constexpr auto kPlayStatusLimit = 2;
@@ -1155,16 +1154,26 @@ void BuildInformationSection(SectionBuilder &builder) {
});
}
const auto kMeta = BuildHelper({
.id = Information::Id(),
.parentId = Main::Id(),
.title = &tr::lng_settings_section_info,
.icon = &st::menuIconProfile,
}, [](SectionBuilder &builder) {
BuildInformationSection(builder);
});
class Information : public Section<Information> {
public:
Information(
QWidget *parent,
not_null<Window::SessionController*> controller);
} // namespace
[[nodiscard]] rpl::producer<QString> title() override;
void showFinished() override;
private:
void setupContent();
QPointer<Ui::RpWidget> _photo;
QPointer<Ui::RpWidget> _uploadPhoto;
QPointer<Ui::RpWidget> _bio;
QPointer<Ui::RpWidget> _colorButton;
QPointer<Ui::RpWidget> _channelButton;
QPointer<Ui::RpWidget> _addAccount;
};
Information::Information(
QWidget *parent,
@@ -1178,46 +1187,126 @@ rpl::producer<QString> Information::title() {
}
void Information::showFinished() {
Section::showFinished();
controller()->checkHighlightControl(u"profile-photo"_q, _photo, {
.shape = HighlightShape::Ellipse,
});
controller()->checkHighlightControl(u"profile-photo/use-emoji"_q, _uploadPhoto, {
.shape = HighlightShape::Ellipse,
});
controller()->checkHighlightControl(u"edit/bio"_q, _bio, {
.margin = st::settingsBioHighlightMargin,
});
controller()->checkHighlightControl(u"edit/your-color"_q, _colorButton);
controller()->checkHighlightControl(u"edit/channel"_q, _channelButton);
controller()->checkHighlightControl(u"edit/add-account"_q, _addAccount);
Section<Information>::showFinished();
}
void Information::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto self = controller()->session().user();
auto targets = InformationHighlightTargets();
const SectionBuildMethod buildMethod = [
photo = &_photo,
uploadPhoto = &_uploadPhoto,
bio = &_bio,
colorButton = &_colorButton,
channelButton = &_channelButton,
addAccount = &_addAccount
](
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
Fn<void(Type)> showOther,
rpl::producer<> showFinished) {
auto &lifetime = container->lifetime();
const auto highlights = lifetime.make_state<HighlightRegistry>();
const auto isPaused = Window::PausedIn(
controller,
Window::GifPauseReason::Layer);
SetupPhoto(content, controller(), self, &targets);
SetupBio(content, self, &targets);
SetupRows(content, controller(), self);
SetupPersonalChannel(content, controller(), self, &targets);
SetupBirthday(content, controller(), self);
SetupAccountsWrap(content, controller(), &targets);
auto builder = SectionBuilder(WidgetContext{
.container = container,
.controller = controller,
.showOther = std::move(showOther),
.isPaused = isPaused,
.highlights = highlights,
});
_photo = targets.photo;
_uploadPhoto = targets.uploadPhoto;
_bio = targets.bio;
_colorButton = targets.colorButton;
_channelButton = targets.channelButton;
_addAccount = targets.addAccount;
const auto self = controller->session().user();
auto targets = InformationHighlightTargets();
build(content, Builder::InformationSection);
SetupPhoto(container, controller, self, &targets);
SetupBio(container, self, &targets);
SetupRows(container, controller, self);
SetupPersonalChannel(container, controller, self, &targets);
SetupBirthday(container, controller, self);
SetupAccountsWrap(container, controller, &targets);
*photo = targets.photo;
*uploadPhoto = targets.uploadPhoto;
*bio = targets.bio;
*colorButton = targets.colorButton;
*channelButton = targets.channelButton;
*addAccount = targets.addAccount;
if (highlights) {
if (*photo) {
highlights->push_back({
u"profile-photo"_q,
{ photo->data(), { .shape = HighlightShape::Ellipse } },
});
}
if (*uploadPhoto) {
highlights->push_back({
u"profile-photo/use-emoji"_q,
{ uploadPhoto->data(), { .shape = HighlightShape::Ellipse } },
});
}
if (*bio) {
highlights->push_back({
u"edit/bio"_q,
{ bio->data(), { .margin = st::settingsBioHighlightMargin } },
});
}
if (*colorButton) {
highlights->push_back({
u"edit/your-color"_q,
{ colorButton->data(), { .rippleShape = true } },
});
}
if (*channelButton) {
highlights->push_back({
u"edit/channel"_q,
{ channelButton->data(), { .rippleShape = true } },
});
}
if (*addAccount) {
highlights->push_back({
u"edit/add-account"_q,
{ addAccount->data(), { .rippleShape = true } },
});
}
}
std::move(showFinished) | rpl::on_next([=] {
for (const auto &[id, entry] : *highlights) {
if (entry.widget) {
controller->checkHighlightControl(
id,
entry.widget,
base::duplicate(entry.args));
}
}
}, lifetime);
};
build(content, buildMethod);
Ui::ResizeFitChild(this, content);
}
const auto kMeta = BuildHelper({
.id = Information::Id(),
.parentId = Main::Id(),
.title = &tr::lng_settings_section_info,
.icon = &st::menuIconProfile,
}, [](SectionBuilder &builder) {
BuildInformationSection(builder);
});
} // namespace
Type InformationId() {
return Information::Id();
}
AccountsEvents SetupAccounts(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
@@ -7,12 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "settings/settings_common_session.h"
#include "settings/settings_type.h"
class UserData;
namespace Ui {
class RpWidget;
class SettingsButton;
class VerticalLayout;
struct UnreadBadgeStyle;
} // namespace Ui
@@ -20,29 +22,13 @@ namespace Main {
class Account;
} // namespace Main
namespace Window {
class SessionController;
} // namespace Window
namespace Settings {
class Information : public Section<Information> {
public:
Information(
QWidget *parent,
not_null<Window::SessionController*> controller);
[[nodiscard]] rpl::producer<QString> title() override;
void showFinished() override;
private:
void setupContent();
QPointer<Ui::RpWidget> _photo;
QPointer<Ui::RpWidget> _uploadPhoto;
QPointer<Ui::RpWidget> _bio;
QPointer<Ui::RpWidget> _colorButton;
QPointer<Ui::RpWidget> _channelButton;
QPointer<Ui::RpWidget> _addAccount;
};
[[nodiscard]] Type InformationId();
struct AccountsEvents {
rpl::producer<> closeRequests;
@@ -73,10 +59,4 @@ void AddUnread(
rpl::producer<UnreadBadge> value);
} // namespace Badge
namespace Builder {
extern SectionBuildMethod InformationSection;
} // namespace Builder
} // namespace Settings
@@ -332,7 +332,7 @@ void BuildSectionButtons(SectionBuilder &builder) {
builder.addSectionButton({
.id = u"main/account"_q,
.title = tr::lng_settings_my_account(),
.targetSection = Information::Id(),
.targetSection = InformationId(),
.icon = { &st::menuIconProfile },
.keywords = { u"profile"_q, u"edit"_q, u"information"_q },
});
@@ -1006,7 +1006,7 @@ void Main::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
if (!controller()->session().supportMode()) {
addAction(
tr::lng_settings_information(tr::now),
[=] { showOther(Information::Id()); },
[=] { showOther(InformationId()); },
&st::menuIconEdit);
}
const auto window = &controller()->window();