From 8c97e5f94263ec2311305880ecd67dd66cdbcfd5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 14 Jan 2026 16:00:02 +0400 Subject: [PATCH] Rewrite settings_local_passcode to new builder pattern Co-Authored-By: Claude Opus 4.5 --- Telegram/CMakeLists.txt | 4 +- .../core/deep_links/deep_links_settings.cpp | 2 +- .../settings_local_passcode.cpp | 392 ++++++++++-------- .../{ => sections}/settings_local_passcode.h | 8 +- .../sections/settings_privacy_security.cpp | 2 +- 5 files changed, 223 insertions(+), 185 deletions(-) rename Telegram/SourceFiles/settings/{ => sections}/settings_local_passcode.cpp (72%) rename Telegram/SourceFiles/settings/{ => sections}/settings_local_passcode.h (74%) diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index ba74247376..458e3c84ac 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1574,8 +1574,8 @@ PRIVATE settings/settings_information.h settings/settings_intro.cpp settings/settings_intro.h - settings/settings_local_passcode.cpp - settings/settings_local_passcode.h + settings/sections/settings_local_passcode.cpp + settings/sections/settings_local_passcode.h settings/sections/settings_main.cpp settings/sections/settings_main.h settings/settings_search.cpp diff --git a/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp b/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp index bac5cf0336..0f18fedecd 100644 --- a/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp +++ b/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp @@ -51,7 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_folders.h" #include "settings/sections/settings_global_ttl.h" #include "settings/settings_information.h" -#include "settings/settings_local_passcode.h" +#include "settings/sections/settings_local_passcode.h" #include "settings/sections/settings_main.h" #include "settings/cloud_password/settings_cloud_password_email_confirm.h" #include "settings/cloud_password/settings_cloud_password_input.h" diff --git a/Telegram/SourceFiles/settings/settings_local_passcode.cpp b/Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp similarity index 72% rename from Telegram/SourceFiles/settings/settings_local_passcode.cpp rename to Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp index aba0d36224..08fae39045 100644 --- a/Telegram/SourceFiles/settings/settings_local_passcode.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp @@ -5,7 +5,7 @@ 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/settings_local_passcode.h" +#include "settings/sections/settings_local_passcode.h" #include "base/platform/base_platform_last_input.h" #include "base/platform/base_platform_info.h" @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "settings/cloud_password/settings_cloud_password_common.h" #include "settings/cloud_password/settings_cloud_password_step.h" +#include "settings/settings_builder.h" #include "settings/settings_common.h" #include "storage/storage_domain.h" #include "ui/vertical_list.h" @@ -37,6 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Settings { namespace { +using namespace Builder; + void SetPasscode( not_null controller, const QString &pass) { @@ -178,7 +181,6 @@ void LocalPasscodeEnter::setupContent() { const auto error = content->add( object_ptr( content, - // Set any text to resize. tr::lng_language_name(tr::now), st::settingLocalPasscodeError), st::changePhoneDescriptionPadding, @@ -381,6 +383,208 @@ public: }; +namespace { + +enum class UnlockType { + None, + Default, + Biometrics, + Companion, +}; + +void BuildManageContent(SectionBuilder &builder) { + const auto controller = builder.controller(); + if (!controller) { + return; + } + + const auto container = builder.container(); + + struct State { + rpl::event_stream<> autoLockBoxClosing; + }; + const auto state = container->lifetime().make_state(); + + builder.addSkip(); + + builder.addButton({ + .id = u"passcode/change"_q, + .title = tr::lng_passcode_change(), + .icon = { &st::menuIconLock }, + .onClick = [=] { + builder.showOther()(LocalPasscodeChange::Id()); + }, + .keywords = { u"password"_q, u"code"_q }, + }); + + auto autolockLabel = state->autoLockBoxClosing.events_starting_with( + {} + ) | rpl::map([] { + const auto autolock = Core::App().settings().autoLock(); + const auto hours = autolock / 3600; + const auto minutes = (autolock - (hours * 3600)) / 60; + + return (hours && minutes) + ? tr::lng_passcode_autolock_hours_minutes( + tr::now, + lt_hours_count, + QString::number(hours), + lt_minutes_count, + QString::number(minutes)) + : minutes + ? tr::lng_minutes(tr::now, lt_count, minutes) + : tr::lng_hours(tr::now, lt_count, hours); + }); + + const auto autoLockButton = builder.addButton({ + .id = u"passcode/auto-lock"_q, + .title = base::Platform::LastUserInputTimeSupported() + ? tr::lng_passcode_autolock_away() + : tr::lng_passcode_autolock_inactive(), + .icon = { &st::menuIconTimer }, + .label = std::move(autolockLabel), + .keywords = { u"timeout"_q, u"lock"_q, u"time"_q }, + }); + if (autoLockButton) { + autoLockButton->addClickHandler([=] { + const auto box = controller->show(Box()); + box->boxClosing( + ) | rpl::start_to_stream(state->autoLockBoxClosing, box->lifetime()); + }); + } + + builder.addSkip(); + + using Divider = CloudPassword::OneEdgeBoxContentDivider; + builder.add([](const WidgetContext &ctx) { + const auto divider = Ui::CreateChild(ctx.container.get()); + divider->lower(); + const auto about = ctx.container->add( + object_ptr>( + ctx.container, + object_ptr( + ctx.container, + rpl::combine( + tr::lng_passcode_about1(), + tr::lng_passcode_about3() + ) | rpl::map([](const QString &s1, const QString &s2) { + return s1 + "\n\n" + s2; + }), + st::boxDividerLabel), + st::defaultBoxDividerLabelPadding)); + about->geometryValue( + ) | rpl::on_next([=](const QRect &r) { + divider->setGeometry(r); + }, divider->lifetime()); + return SectionBuilder::WidgetToAdd{}; + }); + + builder.add([controller](const WidgetContext &ctx) { + const auto systemUnlockWrap = ctx.container->add( + object_ptr>( + ctx.container, + object_ptr(ctx.container)) + )->setDuration(0); + const auto systemUnlockContent = systemUnlockWrap->entity(); + + const auto unlockType = systemUnlockContent->lifetime().make_state< + rpl::variable + >(base::SystemUnlockStatus( + true + ) | rpl::map([](base::SystemUnlockAvailability status) { + return status.withBiometrics + ? UnlockType::Biometrics + : status.withCompanion + ? UnlockType::Companion + : status.available + ? UnlockType::Default + : UnlockType::None; + })); + + unlockType->value( + ) | rpl::on_next([=](UnlockType type) { + while (systemUnlockContent->count()) { + delete systemUnlockContent->widgetAt(0); + } + + Ui::AddSkip(systemUnlockContent); + + const auto biometricsButton = AddButtonWithIcon( + systemUnlockContent, + (Platform::IsWindows() + ? tr::lng_settings_use_winhello() + : (type == UnlockType::Biometrics) + ? tr::lng_settings_use_touchid() + : (type == UnlockType::Companion) + ? tr::lng_settings_use_applewatch() + : tr::lng_settings_use_systempwd()), + st::settingsButton, + { Platform::IsWindows() + ? &st::menuIconWinHello + : (type == UnlockType::Biometrics) + ? &st::menuIconTouchID + : (type == UnlockType::Companion) + ? &st::menuIconAppleWatch + : &st::menuIconSystemPwd }); + biometricsButton->toggleOn( + rpl::single(Core::App().settings().systemUnlockEnabled()) + )->toggledChanges( + ) | rpl::filter([=](bool value) { + return value != Core::App().settings().systemUnlockEnabled(); + }) | rpl::on_next([=](bool value) { + Core::App().settings().setSystemUnlockEnabled(value); + Core::App().saveSettingsDelayed(); + }, systemUnlockContent->lifetime()); + + Ui::AddSkip(systemUnlockContent); + + Ui::AddDividerText( + systemUnlockContent, + (Platform::IsWindows() + ? tr::lng_settings_use_winhello_about() + : (type == UnlockType::Biometrics) + ? tr::lng_settings_use_touchid_about() + : (type == UnlockType::Companion) + ? tr::lng_settings_use_applewatch_about() + : tr::lng_settings_use_systempwd_about())); + + }, systemUnlockContent->lifetime()); + + systemUnlockWrap->toggleOn(unlockType->value( + ) | rpl::map(rpl::mappers::_1 != UnlockType::None)); + + return SectionBuilder::WidgetToAdd{}; + }, [] { + return SearchEntry{ + .id = u"passcode/biometrics"_q, + .title = Platform::IsWindows() + ? tr::lng_settings_use_winhello(tr::now) + : tr::lng_settings_use_touchid(tr::now), + .keywords = { u"biometrics"_q, u"touchid"_q, u"faceid"_q, + u"winhello"_q, u"fingerprint"_q }, + }; + }); + + builder.add(nullptr, [] { + return SearchEntry{ + .id = u"passcode/disable"_q, + .title = tr::lng_settings_passcode_disable(tr::now), + .keywords = { u"disable"_q, u"remove"_q, u"turn off"_q }, + }; + }); +} + +const auto kMeta = BuildHelper({ + .id = LocalPasscodeManageId(), + .parentId = nullptr, + .title = &tr::lng_settings_passcode_title, + .icon = &st::menuIconLock, +}, [](SectionBuilder &builder) { + BuildManageContent(builder); +}); + +} // namespace + class LocalPasscodeManage : public Section { public: LocalPasscodeManage( @@ -402,15 +606,8 @@ private: void setupContent(); rpl::variable _isBottomFillerShown; - - rpl::event_stream<> _showFinished; rpl::event_stream<> _showBack; - QPointer _changeButton; - QPointer _autoLockButton; - QPointer _biometricsButton; - QPointer _disableButton; - }; LocalPasscodeManage::LocalPasscodeManage( @@ -436,168 +633,12 @@ rpl::producer> LocalPasscodeManage::removeFromStack() { void LocalPasscodeManage::setupContent() { const auto content = Ui::CreateChild(this); - struct State { - rpl::event_stream<> autoLockBoxClosing; - }; - const auto state = content->lifetime().make_state(); - CloudPassword::SetupAutoCloseTimer( content->lifetime(), [=] { _showBack.fire({}); }, [] { return Core::App().lastNonIdleTime(); }); - Ui::AddSkip(content); - - const auto changeButton = AddButtonWithIcon( - content, - tr::lng_passcode_change(), - st::settingsButton, - { &st::menuIconLock }); - _changeButton = changeButton; - changeButton->addClickHandler([=] { - showOther(LocalPasscodeChange::Id()); - }); - - auto autolockLabel = state->autoLockBoxClosing.events_starting_with( - {} - ) | rpl::map([] { - const auto autolock = Core::App().settings().autoLock(); - const auto hours = autolock / 3600; - const auto minutes = (autolock - (hours * 3600)) / 60; - - return (hours && minutes) - ? tr::lng_passcode_autolock_hours_minutes( - tr::now, - lt_hours_count, - QString::number(hours), - lt_minutes_count, - QString::number(minutes)) - : minutes - ? tr::lng_minutes(tr::now, lt_count, minutes) - : tr::lng_hours(tr::now, lt_count, hours); - }); - - const auto autoLockButton = AddButtonWithLabel( - content, - (base::Platform::LastUserInputTimeSupported() - ? tr::lng_passcode_autolock_away - : tr::lng_passcode_autolock_inactive)(), - std::move(autolockLabel), - st::settingsButton, - { &st::menuIconTimer }); - _autoLockButton = autoLockButton; - autoLockButton->addClickHandler([=] { - const auto box = controller()->show(Box()); - box->boxClosing( - ) | rpl::start_to_stream(state->autoLockBoxClosing, box->lifetime()); - }); - - Ui::AddSkip(content); - - using Divider = CloudPassword::OneEdgeBoxContentDivider; - const auto divider = Ui::CreateChild(this); - divider->lower(); - const auto about = content->add( - object_ptr>( - content, - object_ptr( - content, - rpl::combine( - tr::lng_passcode_about1(), - tr::lng_passcode_about3() - ) | rpl::map([](const QString &s1, const QString &s2) { - return s1 + "\n\n" + s2; - }), - st::boxDividerLabel), - st::defaultBoxDividerLabelPadding)); - about->geometryValue( - ) | rpl::on_next([=](const QRect &r) { - divider->setGeometry(r); - }, divider->lifetime()); - _isBottomFillerShown.value( - ) | rpl::on_next([=](bool shown) { - divider->skipEdge(Qt::BottomEdge, shown); - }, divider->lifetime()); - - const auto systemUnlockWrap = content->add( - object_ptr>( - content, - object_ptr(content)) - )->setDuration(0); - const auto systemUnlockContent = systemUnlockWrap->entity(); - - enum class UnlockType { - None, - Default, - Biometrics, - Companion, - }; - const auto unlockType = systemUnlockContent->lifetime().make_state< - rpl::variable - >(base::SystemUnlockStatus( - true - ) | rpl::map([](base::SystemUnlockAvailability status) { - return status.withBiometrics - ? UnlockType::Biometrics - : status.withCompanion - ? UnlockType::Companion - : status.available - ? UnlockType::Default - : UnlockType::None; - })); - - unlockType->value( - ) | rpl::on_next([=](UnlockType type) { - while (systemUnlockContent->count()) { - delete systemUnlockContent->widgetAt(0); - } - - Ui::AddSkip(systemUnlockContent); - - const auto biometricsButton = AddButtonWithIcon( - systemUnlockContent, - (Platform::IsWindows() - ? tr::lng_settings_use_winhello() - : (type == UnlockType::Biometrics) - ? tr::lng_settings_use_touchid() - : (type == UnlockType::Companion) - ? tr::lng_settings_use_applewatch() - : tr::lng_settings_use_systempwd()), - st::settingsButton, - { Platform::IsWindows() - ? &st::menuIconWinHello - : (type == UnlockType::Biometrics) - ? &st::menuIconTouchID - : (type == UnlockType::Companion) - ? &st::menuIconAppleWatch - : &st::menuIconSystemPwd }); - _biometricsButton = biometricsButton; - biometricsButton->toggleOn( - rpl::single(Core::App().settings().systemUnlockEnabled()) - )->toggledChanges( - ) | rpl::filter([=](bool value) { - return value != Core::App().settings().systemUnlockEnabled(); - }) | rpl::on_next([=](bool value) { - Core::App().settings().setSystemUnlockEnabled(value); - Core::App().saveSettingsDelayed(); - }, systemUnlockContent->lifetime()); - - Ui::AddSkip(systemUnlockContent); - - Ui::AddDividerText( - systemUnlockContent, - (Platform::IsWindows() - ? tr::lng_settings_use_winhello_about() - : (type == UnlockType::Biometrics) - ? tr::lng_settings_use_touchid_about() - : (type == UnlockType::Companion) - ? tr::lng_settings_use_applewatch_about() - : tr::lng_settings_use_systempwd_about())); - - }, systemUnlockContent->lifetime()); - - systemUnlockWrap->toggleOn(unlockType->value( - ) | rpl::map(rpl::mappers::_1 != UnlockType::None)); + build(content, Builder::LocalPasscodeManageSection); Ui::ResizeFitChild(this, content); } @@ -633,24 +674,12 @@ base::weak_qptr LocalPasscodeManage::createPinnedToBottom( std::move(callback)); _isBottomFillerShown = base::take(bottomButton.isBottomFillerShown); - _disableButton = bottomButton.button.get(); return bottomButton.content; } void LocalPasscodeManage::showFinished() { - _showFinished.fire({}); - - controller()->checkHighlightControl(u"passcode/change"_q, _changeButton); - controller()->checkHighlightControl( - u"passcode/auto-lock"_q, - _autoLockButton); - controller()->checkHighlightControl( - u"passcode/biometrics"_q, - _biometricsButton); - controller()->checkHighlightControl( - u"passcode/disable"_q, - _disableButton); + Section::showFinished(); } rpl::producer<> LocalPasscodeManage::sectionShowBack() { @@ -671,4 +700,9 @@ Type LocalPasscodeManageId() { return LocalPasscodeManage::Id(); } +namespace Builder { + +SectionBuildMethod LocalPasscodeManageSection = kMeta.build; + +} // namespace Builder } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_local_passcode.h b/Telegram/SourceFiles/settings/sections/settings_local_passcode.h similarity index 74% rename from Telegram/SourceFiles/settings/settings_local_passcode.h rename to Telegram/SourceFiles/settings/sections/settings_local_passcode.h index 1f307189c5..39bfea2433 100644 --- a/Telegram/SourceFiles/settings/settings_local_passcode.h +++ b/Telegram/SourceFiles/settings/sections/settings_local_passcode.h @@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "settings/settings_type.h" +#include "settings/settings_common.h" namespace Settings { @@ -15,5 +15,9 @@ Type LocalPasscodeCreateId(); Type LocalPasscodeCheckId(); Type LocalPasscodeManageId(); -} // namespace Settings +namespace Builder { +extern SectionBuildMethod LocalPasscodeManageSection; + +} // namespace Builder +} // namespace Settings diff --git a/Telegram/SourceFiles/settings/sections/settings_privacy_security.cpp b/Telegram/SourceFiles/settings/sections/settings_privacy_security.cpp index 2db21ebb8c..047ef79657 100644 --- a/Telegram/SourceFiles/settings/sections/settings_privacy_security.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_privacy_security.cpp @@ -46,7 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_active_sessions.h" #include "settings/settings_blocked_peers.h" #include "settings/sections/settings_global_ttl.h" -#include "settings/settings_local_passcode.h" +#include "settings/sections/settings_local_passcode.h" #include "settings/settings_passkeys.h" #include "settings/settings_premium.h" #include "settings/settings_privacy_controllers.h"