From 1e5a93249cc14ff0727884caff5ca4cc9e7ab097 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 9 Jan 2026 17:12:54 +0400 Subject: [PATCH] Support all required deep links. --- Telegram/SourceFiles/boxes/connection_box.cpp | 51 +- Telegram/SourceFiles/boxes/connection_box.h | 8 +- .../SourceFiles/boxes/edit_privacy_box.cpp | 21 +- Telegram/SourceFiles/boxes/edit_privacy_box.h | 3 +- Telegram/SourceFiles/boxes/language_box.cpp | 36 +- Telegram/SourceFiles/boxes/language_box.h | 13 +- .../SourceFiles/boxes/local_storage_box.cpp | 31 +- .../SourceFiles/boxes/local_storage_box.h | 6 +- .../boxes/moderate_messages_box.cpp | 2 +- .../boxes/peers/edit_participant_box.cpp | 4 +- .../boxes/peers/edit_peer_permissions_box.cpp | 22 +- .../boxes/peers/edit_peer_permissions_box.h | 5 +- Telegram/SourceFiles/boxes/stickers_box.cpp | 24 +- .../calls/calls_box_controller.cpp | 12 +- .../SourceFiles/calls/calls_box_controller.h | 4 +- .../core/deep_links/deep_links_settings.cpp | 629 ++++++++++++++---- .../SourceFiles/core/local_url_handlers.cpp | 2 +- .../admin_log/history_admin_log_filter.cpp | 2 +- .../SourceFiles/info/info_wrap_widget.cpp | 18 +- .../stories/info_stories_inner_widget.cpp | 23 + .../builder/settings_advanced_builder.cpp | 3 +- .../settings/builder/settings_builder.cpp | 15 +- .../settings/builder/settings_builder.h | 1 + .../builder/settings_chat_builder.cpp | 21 +- .../builder/settings_main_builder.cpp | 18 +- .../settings_privacy_security_builder.cpp | 6 +- .../settings_cloud_password_common.cpp | 7 +- .../settings_cloud_password_common.h | 1 + .../settings_cloud_password_manage.cpp | 43 +- .../settings/settings_advanced.cpp | 2 +- .../settings/settings_business.cpp | 8 +- .../SourceFiles/settings/settings_chat.cpp | 194 +++++- Telegram/SourceFiles/settings/settings_chat.h | 29 +- .../SourceFiles/settings/settings_common.cpp | 5 + .../SourceFiles/settings/settings_common.h | 2 + .../settings/settings_global_ttl.cpp | 13 +- .../settings/settings_local_passcode.cpp | 54 +- .../SourceFiles/settings/settings_main.cpp | 35 + Telegram/SourceFiles/settings/settings_main.h | 1 + .../settings/settings_passkeys.cpp | 39 +- .../settings/settings_power_saving.cpp | 18 +- .../settings/settings_power_saving.h | 7 +- .../settings/settings_privacy_controllers.cpp | 3 +- .../settings/settings_privacy_security.cpp | 48 +- .../settings/settings_privacy_security.h | 11 +- .../settings/settings_websites.cpp | 21 +- .../SourceFiles/settings/settings_websites.h | 8 + .../ui/controls/userpic_button.cpp | 5 +- .../SourceFiles/window/window_main_menu.cpp | 6 +- 49 files changed, 1247 insertions(+), 293 deletions(-) diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index 1198f1e501..8902fc2c26 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/local_url_handlers.h" #include "lang/lang_keys.h" #include "main/main_account.h" +#include "main/main_session.h" #include "mtproto/facade.h" #include "settings/settings_common.h" #include "storage/localstorage.h" @@ -352,10 +353,12 @@ public: ProxiesBox( QWidget*, not_null controller, - Core::SettingsProxy &settings); + Core::SettingsProxy &settings, + const QString &highlightId = QString()); protected: void prepare() override; + void showFinished() override; void keyPressEvent(QKeyEvent *e) override; private: @@ -381,6 +384,10 @@ private: base::flat_map> _rows; + QPointer _addProxyButton; + QPointer _shareListButton; + QString _highlightId; + }; class ProxyBox final : public Ui::BoxContent { @@ -749,10 +756,12 @@ void ProxyRow::showMenu() { ProxiesBox::ProxiesBox( QWidget*, not_null controller, - Core::SettingsProxy &settings) + Core::SettingsProxy &settings, + const QString &highlightId) : _controller(controller) , _settings(settings) -, _initialWrap(this) { +, _initialWrap(this) +, _highlightId(highlightId) { _controller->views( ) | rpl::on_next([=](View &&view) { applyView(std::move(view)); @@ -774,13 +783,29 @@ void ProxiesBox::keyPressEvent(QKeyEvent *e) { void ProxiesBox::prepare() { setTitle(tr::lng_proxy_settings()); - addButton(tr::lng_proxy_add(), [=] { addNewProxy(); }); + _addProxyButton = addButton(tr::lng_proxy_add(), [=] { addNewProxy(); }); addButton(tr::lng_close(), [=] { closeBox(); }); setupTopButton(); setupContent(); } +void ProxiesBox::showFinished() { + if (_highlightId == u"proxy/add-proxy"_q) { + if (_addProxyButton) { + _highlightId = QString(); + Settings::HighlightWidget( + _addProxyButton, + { .rippleShape = true }); + } + } else if (_highlightId == u"proxy/share-list"_q) { + if (_shareListButton) { + _highlightId = QString(); + Settings::HighlightWidget(_shareListButton); + } + } +} + void ProxiesBox::setupTopButton() { const auto top = addTopButton(st::infoTopBarMenu); const auto menu @@ -923,6 +948,7 @@ void ProxiesBox::setupContent() { tr::lng_proxy_edit_share_list_button(), st::settingsButton, { &st::menuIconCopy }); + _shareListButton = shareList; shareList->setClickedCallback([=] { _controller->shareItems(); }); @@ -1514,15 +1540,17 @@ void ProxiesBoxController::setupChecker(int id, const Checker &checker) { } object_ptr ProxiesBoxController::CreateOwningBox( - not_null account) { + not_null account, + const QString &highlightId) { auto controller = std::make_unique(account); - auto box = controller->create(); + auto box = controller->create(highlightId); Ui::AttachAsChild(box, std::move(controller)); return box; } -object_ptr ProxiesBoxController::create() { - auto result = Box(this, _settings); +object_ptr ProxiesBoxController::create( + const QString &highlightId) { + auto result = Box(this, _settings, highlightId); _show = result->uiShow(); for (const auto &item : _list) { updateView(item); @@ -1848,6 +1876,13 @@ void ProxiesBoxController::share(const ProxyData &proxy, bool qr) { _show->showToast(tr::lng_username_copied(tr::now)); } +void ProxiesBoxController::Show( + not_null controller, + const QString &highlightId) { + controller->show( + CreateOwningBox(&controller->session().account(), highlightId)); +} + ProxiesBoxController::~ProxiesBoxController() { if (_saveTimer.isActive()) { base::call_delayed( diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index 97636060c7..fcbe5ad6f6 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -47,8 +47,12 @@ public: const QMap &fields); static object_ptr CreateOwningBox( - not_null account); - object_ptr create(); + not_null account, + const QString &highlightId = QString()); + static void Show( + not_null controller, + const QString &highlightId = QString()); + object_ptr create(const QString &highlightId = QString()); enum class ItemState { Connecting, diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index f423ea1d4d..7541cdbc42 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "main/main_app_config.h" #include "main/main_session.h" +#include "settings/settings_common.h" #include "settings/settings_premium.h" #include "settings/settings_privacy_controllers.h" #include "settings/settings_privacy_security.h" @@ -962,7 +963,8 @@ void EditPrivacyBox::showFinished() { void EditMessagesPrivacyBox( not_null box, - not_null controller) { + not_null controller, + const QString &highlightControlId) { box->setTitle(tr::lng_messages_privacy_title()); box->setWidth(st::boxWideWidth); @@ -979,6 +981,9 @@ void EditMessagesPrivacyBox( const auto inner = box->verticalLayout(); inner->add(object_ptr(box)); + auto highlightCharged = (Ui::RpWidget*)nullptr; + auto highlightRemoveFee = (Ui::RpWidget*)nullptr; + Ui::AddSkip(inner, st::messagePrivacyTopSkip); Ui::AddSubsectionTitle(inner, tr::lng_messages_privacy_subtitle()); const auto group = std::make_shared( @@ -1028,6 +1033,7 @@ void EditMessagesPrivacyBox( 0, st::messagePrivacyBottomSkip)) : nullptr; + highlightCharged = charged; struct State { rpl::variable stars; @@ -1077,6 +1083,7 @@ void EditMessagesPrivacyBox( tr::lng_messages_privacy_remove_fee(), std::move(label), st::settingsButtonNoIcon); + highlightRemoveFee = exceptions; const auto shower = exceptions->lifetime().make_state(); exceptions->setClickedCallback([=] { @@ -1174,6 +1181,18 @@ void EditMessagesPrivacyBox( box->closeBox(); }); } + + if (!highlightControlId.isEmpty()) { + box->showFinishes() | rpl::take(1) | rpl::on_next([=] { + if (highlightControlId == u"privacy/set-price"_q) { + Settings::HighlightWidget( + highlightCharged, + { .radius = st::boxRadius }); + } else if (highlightControlId == u"privacy/remove-fee"_q) { + Settings::HighlightWidget(highlightRemoveFee); + } + }, box->lifetime()); + } } rpl::producer SetupChargeSlider( diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index 5aa42488ef..4265cba9b1 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -175,7 +175,8 @@ private: void EditMessagesPrivacyBox( not_null box, - not_null controller); + not_null controller, + const QString &highlightControlId = QString()); [[nodiscard]] rpl::producer SetupChargeSlider( not_null container, diff --git a/Telegram/SourceFiles/boxes/language_box.cpp b/Telegram/SourceFiles/boxes/language_box.cpp index 7a13939ebc..c55423eca5 100644 --- a/Telegram/SourceFiles/boxes/language_box.cpp +++ b/Telegram/SourceFiles/boxes/language_box.cpp @@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_cloud_manager.h" #include "settings/settings_common.h" #include "spellcheck/spellcheck_types.h" +#include "window/window_controller.h" #include "window/window_session_controller.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" @@ -1102,8 +1103,12 @@ Ui::ScrollToRequest Content::jump(int rows) { } // namespace -LanguageBox::LanguageBox(QWidget*, Window::SessionController *controller) -: _controller(controller) { +LanguageBox::LanguageBox( + QWidget*, + Window::SessionController *controller, + const QString &highlightId) +: _controller(controller) +, _highlightId(highlightId) { } void LanguageBox::prepare() { @@ -1176,6 +1181,22 @@ void LanguageBox::prepare() { }; } +void LanguageBox::showFinished() { + if (_controller && !_highlightId.isEmpty()) { + if (const auto window = Core::App().findWindow(this)) { + window->checkHighlightControl( + u"language/show-button"_q, + _showButtonToggle.data()); + window->checkHighlightControl( + u"language/translate-chats"_q, + _translateChatsToggle.data()); + window->checkHighlightControl( + u"language/do-not-translate"_q, + _doNotTranslateButton.data()); + } + } +} + void LanguageBox::setupTop(not_null container) { if (!_controller) { return; @@ -1186,6 +1207,7 @@ void LanguageBox::setupTop(not_null container) { tr::lng_translate_settings_show(), st::settingsButtonNoIcon))->toggleOn( rpl::single(Core::App().settings().translateButtonEnabled())); + _showButtonToggle = translateEnabled; translateEnabled->toggledValue( ) | rpl::filter([](bool checked) { @@ -1207,6 +1229,7 @@ void LanguageBox::setupTop(not_null container) { rpl::duplicate(premium), _1 && _2), _translateChatTurnOff.events())); + _translateChatsToggle = translateChat; std::move(premium) | rpl::on_next([=](bool value) { translateChat->setToggleLocked(!value); }, translateChat->lifetime()); @@ -1249,6 +1272,7 @@ void LanguageBox::setupTop(not_null container) { : Ui::LanguageName(list.front()); }), st::settingsButtonNoIcon); + _doNotTranslateButton = translateSkip; translateSkip->setClickedCallback([=] { uiShow()->showBox(Ui::EditSkipTranslationLanguages()); @@ -1288,7 +1312,9 @@ void LanguageBox::setInnerFocus() { _setInnerFocus(); } -base::binary_guard LanguageBox::Show(Window::SessionController *controller) { +base::binary_guard LanguageBox::Show( + Window::SessionController *controller, + const QString &highlightId) { auto result = base::binary_guard(); auto &manager = Lang::CurrentCloudManager(); @@ -1306,11 +1332,11 @@ base::binary_guard LanguageBox::Show(Window::SessionController *controller) { base::take(lifetime)->destroy(); } if (show) { - Ui::show(Box(weak.get())); + Ui::show(Box(weak.get(), highlightId)); } }, *lifetime); } else { - Ui::show(Box(controller)); + Ui::show(Box(controller, highlightId)); } manager.requestLanguageList(); diff --git a/Telegram/SourceFiles/boxes/language_box.h b/Telegram/SourceFiles/boxes/language_box.h index e6998474df..d3b89a509f 100644 --- a/Telegram/SourceFiles/boxes/language_box.h +++ b/Telegram/SourceFiles/boxes/language_box.h @@ -24,15 +24,20 @@ class SessionController; class LanguageBox : public Ui::BoxContent { public: - LanguageBox(QWidget*, Window::SessionController *controller); + LanguageBox( + QWidget*, + Window::SessionController *controller, + const QString &highlightId = QString()); void setInnerFocus() override; [[nodiscard]] static base::binary_guard Show( - Window::SessionController *controller); + Window::SessionController *controller, + const QString &highlightId = QString()); protected: void prepare() override; + void showFinished() override; void keyPressEvent(QKeyEvent *e) override; @@ -41,6 +46,10 @@ private: [[nodiscard]] int rowsInPage() const; Window::SessionController *_controller = nullptr; + QString _highlightId; + QPointer _showButtonToggle; + QPointer _translateChatsToggle; + QPointer _doNotTranslateButton; rpl::event_stream _translateChatTurnOff; Fn _setInnerFocus; Fn _jump; diff --git a/Telegram/SourceFiles/boxes/local_storage_box.cpp b/Telegram/SourceFiles/boxes/local_storage_box.cpp index 4432a32349..3936aeb492 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.cpp +++ b/Telegram/SourceFiles/boxes/local_storage_box.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "lang/lang_keys.h" #include "main/main_session.h" +#include "settings/settings_common.h" #include "window/window_session_controller.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" @@ -132,6 +133,7 @@ public: void toggleProgress(bool shown); rpl::producer<> clearRequests() const; + [[nodiscard]] not_null clearButton() const; protected: int resizeGetHeight(int newWidth) override; @@ -210,6 +212,10 @@ rpl::producer<> LocalStorageBox::Row::clearRequests() const { return _clear->clicks() | rpl::to_empty; } +not_null LocalStorageBox::Row::clearButton() const { + return _clear.data(); +} + int LocalStorageBox::Row::resizeGetHeight(int newWidth) { const auto height = st::localStorageRowHeight; const auto padding = st::localStorageRowPadding; @@ -281,10 +287,13 @@ LocalStorageBox::LocalStorageBox( _timeLimit = settings.totalTimeLimit; } -void LocalStorageBox::Show(not_null controller) { +void LocalStorageBox::Show( + not_null controller, + const QString &highlightId) { auto shared = std::make_shared>( Box(&controller->session(), CreateTag())); const auto weak = shared->data(); + weak->_highlightId = highlightId; rpl::combine( controller->session().data().cache().statsOnMain(), controller->session().data().cacheBigFile().statsOnMain() @@ -306,6 +315,26 @@ void LocalStorageBox::prepare() { setupControls(); } +void LocalStorageBox::showFinished() { + if (_highlightId.isEmpty()) { + return; + } + if (_highlightId == u"storage/clear-cache"_q) { + if (const auto i = _rows.find(0); i != _rows.end()) { + Settings::HighlightWidget( + i->second->entity()->clearButton(), + { .rippleShape = true }); + } + } else if (_highlightId == u"storage/max-cache"_q) { + if (_totalSlider) { + const auto add = st::roundRadiusSmall; + Settings::HighlightWidget( + _totalSlider, + { .margin = { -add, -add, -add, -add }, .radius = add }); + } + } +} + void LocalStorageBox::updateRow( not_null*> row, const Database::TaggedSummary *data) { diff --git a/Telegram/SourceFiles/boxes/local_storage_box.h b/Telegram/SourceFiles/boxes/local_storage_box.h index cc9e01b571..b9de021e9a 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.h +++ b/Telegram/SourceFiles/boxes/local_storage_box.h @@ -44,10 +44,13 @@ public: not_null session, CreateTag); - static void Show(not_null controller); + static void Show( + not_null controller, + const QString &highlightId = QString()); protected: void prepare() override; + void showFinished() override; private: class Row; @@ -102,5 +105,6 @@ private: int64 _mediaSizeLimit = 0; size_type _timeLimit = 0; bool _limitsChanged = false; + QString _highlightId; }; diff --git a/Telegram/SourceFiles/boxes/moderate_messages_box.cpp b/Telegram/SourceFiles/boxes/moderate_messages_box.cpp index f0ad87172e..2b9bc8a961 100644 --- a/Telegram/SourceFiles/boxes/moderate_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/moderate_messages_box.cpp @@ -824,7 +824,7 @@ void CreateModerateMessagesBox( tr::lng_restrict_users_part_header( lt_count, rpl::single(participants.size()) | tr::to_count()))); - auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( + auto [checkboxes, getRestrictions, changes, highlightWidget] = CreateEditRestrictions( box, prepareFlags, disabledMessages, diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index cf66326954..5f6a43e957 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -368,7 +368,7 @@ void EditAdminBox::prepare() { .anyoneCanAddMembers = anyoneCanAddMembers, }; Ui::AddSubsectionTitle(inner, tr::lng_rights_edit_admin_header()); - auto [checkboxes, getChecked, changes] = CreateEditAdminRights( + auto [checkboxes, getChecked, changes, highlightWidget] = CreateEditAdminRights( inner, prepareFlags, disabledMessages, @@ -799,7 +799,7 @@ void EditRestrictedBox::prepare() { Ui::AddSubsectionTitle( verticalLayout(), tr::lng_rights_user_restrictions_header()); - auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( + auto [checkboxes, getRestrictions, changes, highlightWidget] = CreateEditRestrictions( this, prepareFlags, disabledMessages, diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp index 88eb87ecd9..df903d6ade 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp @@ -712,6 +712,8 @@ template return checkView; }; + auto highlightWidget = QPointer(); + const auto highlightFlags = descriptor.highlightFlags; for (const auto &nestedWithLabel : descriptor.labels) { Assert(!nestedWithLabel.nested.empty()); @@ -723,16 +725,18 @@ template : object_ptr>{ nullptr }; const auto verticalLayout = wrap ? wrap->entity() : container.get(); auto innerChecks = std::vector>(); + auto sectionFlags = Flags(); for (const auto &entry : nestedWithLabel.nested) { const auto c = addCheckbox(verticalLayout, isInner, entry); if (isInner) { innerChecks.push_back(c); + sectionFlags |= entry.flags; } } if (wrap) { const auto raw = wrap.data(); raw->hide(anim::type::instant); - AddInnerToggle( + const auto toggle = AddInnerToggle( container, st, innerChecks, @@ -740,6 +744,9 @@ template *nestedWithLabel.nestingLabel, std::nullopt, { nestedWithLabel.nested.front().icon }); + if (highlightFlags && (sectionFlags & highlightFlags)) { + highlightWidget = toggle; + } container->add(std::move(wrap)); container->widthValue( ) | rpl::on_next([=](int w) { @@ -754,9 +761,10 @@ template } return { - nullptr, - value, - state->anyChanges.events() | rpl::map(value) + .widget = nullptr, + .value = value, + .changes = state->anyChanges.events() | rpl::map(value), + .highlightWidget = highlightWidget, }; } @@ -1143,7 +1151,7 @@ void ShowEditPeerPermissionsBox( Ui::AddSubsectionTitle( inner, tr::lng_rights_default_restrictions_header()); - auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( + auto [checkboxes, getRestrictions, changes, highlightWidget] = CreateEditRestrictions( inner, restrictions, disabledMessages, @@ -1461,10 +1469,12 @@ ChatAdminRights AdminRightsForOwnershipTransfer( EditFlagsControl CreateEditPowerSaving( QWidget *parent, PowerSaving::Flags flags, - rpl::producer forceDisabledMessage) { + rpl::producer forceDisabledMessage, + PowerSaving::Flags highlightFlags) { auto widget = object_ptr(parent); auto descriptor = Settings::PowerSavingLabels(); descriptor.forceDisabledMessage = std::move(forceDisabledMessage); + descriptor.highlightFlags = highlightFlags; auto result = CreateEditFlags( widget.data(), flags, diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h index 018b5523dc..4d7ed413c7 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h @@ -69,6 +69,7 @@ struct EditFlagsControl { object_ptr widget; Fn value; rpl::producer changes; + QPointer highlightWidget; }; template @@ -83,6 +84,7 @@ struct EditFlagsDescriptor { base::flat_map disabledMessages; const style::SettingsButton *st = nullptr; rpl::producer forceDisabledMessage; + Flags highlightFlags = Flags(); }; using RestrictionLabel = EditFlagsLabel; @@ -117,7 +119,8 @@ using AdminRightLabel = EditFlagsLabel; [[nodiscard]] auto CreateEditPowerSaving( QWidget *parent, PowerSaving::Flags flags, - rpl::producer forceDisabledMessage + rpl::producer forceDisabledMessage, + PowerSaving::Flags highlightFlags = PowerSaving::Flags() ) -> EditFlagsControl; [[nodiscard]] auto CreateEditAdminLogFilter( diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 4e59808196..ed4a7d02c7 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -750,28 +750,28 @@ void StickersBox::refreshTabs() { sections.push_back(tr::lng_stickers_masks_tab(tr::now)); _tabIndices.push_back(Section::Masks); } - if (!stickers.featuredSetsOrder().isEmpty() && _featured.widget()) { + const auto showFeatured = _featured.widget() + && (!stickers.featuredSetsOrder().isEmpty() + || _section == Section::Featured); + if (showFeatured) { sections.push_back(tr::lng_stickers_featured_tab(tr::now)); _tabIndices.push_back(Section::Featured); } - if (!archivedSetsOrder().isEmpty() && _archived.widget()) { + const auto showArchived = _archived.widget() + && (!archivedSetsOrder().isEmpty() + || _section == Section::Archived); + if (showArchived) { sections.push_back(tr::lng_stickers_archived_tab(tr::now)); _tabIndices.push_back(Section::Archived); } _tabs->setSections(sections); - if ((_tab == &_archived && !_tabIndices.contains(Section::Archived)) - || (_tab == &_featured && !_tabIndices.contains(Section::Featured)) - || (_tab == &_masks && !_tabIndices.contains(Section::Masks))) { + if ((_section == Section::Archived && !_tabIndices.contains(Section::Archived)) + || (_section == Section::Featured && !_tabIndices.contains(Section::Featured)) + || (_section == Section::Masks && !_tabIndices.contains(Section::Masks))) { switchTab(); } else { _ignoreTabActivation = true; - _tabs->setActiveSectionFast(_tabIndices.indexOf((_tab == &_archived) - ? Section::Archived - : (_tab == &_featured) - ? Section::Featured - : (_tab == &_masks) - ? Section::Masks - : Section::Installed)); + _tabs->setActiveSectionFast(_tabIndices.indexOf(_section)); _ignoreTabActivation = false; } updateTabsGeometry(); diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index d7062d5225..19ec51f14d 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "info/profile/info_profile_icon.h" #include "settings/settings_calls.h" +#include "settings/settings_common.h" #include "styles/style_info.h" // infoTopBarMenu #include "styles/style_layers.h" // st::boxLabel. #include "styles/style_calls.h" @@ -803,7 +804,9 @@ void ClearCallsBox( return result; } -void ShowCallsBox(not_null<::Window::SessionController*> window) { +void ShowCallsBox( + not_null<::Window::SessionController*> window, + bool highlightStartCall) { struct State { State(not_null<::Window::SessionController*> window) : callsController(window) @@ -893,6 +896,13 @@ void ShowCallsBox(not_null<::Window::SessionController*> window) { state->menu->popup(QCursor::pos()); return true; }); + + if (highlightStartCall) { + box->showFinishes( + ) | rpl::take(1) | rpl::on_next([=] { + Settings::HighlightWidget(button); + }, box->lifetime()); + } })); } diff --git a/Telegram/SourceFiles/calls/calls_box_controller.h b/Telegram/SourceFiles/calls/calls_box_controller.h index 9c183f1088..d9ef0ccccb 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.h +++ b/Telegram/SourceFiles/calls/calls_box_controller.h @@ -81,6 +81,8 @@ void ClearCallsBox( not_null box, not_null<::Window::SessionController*> window); -void ShowCallsBox(not_null<::Window::SessionController*> window); +void ShowCallsBox( + not_null<::Window::SessionController*> window, + bool highlightStartCall = false); } // namespace Calls diff --git a/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp b/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp index b1999f148b..2d42e7e1f4 100644 --- a/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp +++ b/Telegram/SourceFiles/core/deep_links/deep_links_settings.cpp @@ -10,9 +10,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "base/binary_guard.h" #include "boxes/add_contact_box.h" +#include "boxes/gift_credits_box.h" #include "boxes/language_box.h" +#include "boxes/stickers_box.h" +#include "chat_helpers/emoji_sets_manager.h" #include "boxes/edit_privacy_box.h" #include "boxes/peers/edit_peer_color_box.h" +#include "info/bot/earn/info_bot_earn_widget.h" +#include "info/bot/starref/info_bot_starref_common.h" +#include "info/bot/starref/info_bot_starref_join_widget.h" #include "settings/settings_privacy_controllers.h" #include "ui/chat/chat_style.h" #include "boxes/star_gift_box.h" @@ -24,36 +30,77 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "data/notify/data_notify_settings.h" #include "info/info_memento.h" +#include "info/peer_gifts/info_peer_gifts_widget.h" #include "info/stories/info_stories_widget.h" #include "lang/lang_keys.h" #include "ui/boxes/peer_qr_box.h" #include "ui/layers/generic_box.h" +#include "main/main_domain.h" #include "main/main_session.h" +#include "storage/storage_domain.h" #include "settings/settings_active_sessions.h" #include "settings/settings_advanced.h" #include "settings/settings_blocked_peers.h" #include "settings/settings_business.h" #include "settings/settings_calls.h" #include "settings/settings_chat.h" +#include "settings/settings_passkeys.h" +#include "data/components/passkeys.h" +#include "calls/calls_box_controller.h" #include "settings/settings_credits.h" #include "settings/settings_folders.h" #include "settings/settings_global_ttl.h" #include "settings/settings_information.h" #include "settings/settings_local_passcode.h" #include "settings/settings_main.h" +#include "settings/cloud_password/settings_cloud_password_email_confirm.h" +#include "settings/cloud_password/settings_cloud_password_input.h" +#include "settings/cloud_password/settings_cloud_password_start.h" +#include "api/api_cloud_password.h" +#include "core/core_cloud_password.h" #include "settings/settings_notifications.h" #include "settings/settings_notifications_type.h" +#include "settings/settings_power_saving.h" #include "settings/settings_premium.h" +#include "ui/power_saving.h" #include "settings/settings_privacy_security.h" #include "settings/settings_websites.h" +#include "boxes/connection_box.h" +#include "boxes/local_storage_box.h" +#include "mainwindow.h" #include "window/window_session_controller.h" namespace Core::DeepLinks { namespace { -Result ShowLanguageBox(const Context &ctx) { +Result ShowLanguageBox(const Context &ctx, const QString &highlightId = QString()) { static auto Guard = base::binary_guard(); - Guard = LanguageBox::Show(ctx.controller); + if (!highlightId.isEmpty() && ctx.controller) { + ctx.controller->setHighlightControlId(highlightId); + } + Guard = LanguageBox::Show(ctx.controller, highlightId); + return Result::Handled; +} + +Result ShowPowerSavingBox( + const Context &ctx, + PowerSaving::Flags highlightFlags = PowerSaving::Flags()) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show( + Box(::Settings::PowerSavingBox, highlightFlags), + Ui::LayerOption::KeepOther, + anim::type::normal); + return Result::Handled; +} + +Result ShowMainMenuWithHighlight(const Context &ctx, const QString &highlightId) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->setHighlightControlId(highlightId); + ctx.controller->widget()->showMainMenu(); return Result::Handled; } @@ -61,7 +108,9 @@ Result ShowSavedMessages(const Context &ctx) { if (!ctx.controller) { return Result::NeedsAuth; } - ctx.controller->showPeerHistory(ctx.controller->session().userPeerId()); + ctx.controller->showPeerHistory( + ctx.controller->session().userPeerId(), + Window::SectionShow::Way::Forward); return Result::Handled; } @@ -178,6 +227,49 @@ Result ShowLogOutMenu(const Context &ctx) { return Result::Handled; } +Result ShowPasskeys(const Context &ctx, bool highlightCreate) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + const auto controller = ctx.controller; + const auto session = &controller->session(); + const auto showBox = [=] { + if (highlightCreate) { + controller->setHighlightControlId(u"passkeys/create"_q); + } + if (session->passkeys().list().empty()) { + controller->show(Box([=](not_null box) { + ::Settings::PasskeysNoneBox(box, session); + box->boxClosing() | rpl::on_next([=] { + if (!session->passkeys().list().empty()) { + controller->showSettings(::Settings::PasskeysId()); + } + }, box->lifetime()); + })); + } else { + controller->showSettings(::Settings::PasskeysId()); + } + }; + if (session->passkeys().listKnown()) { + showBox(); + } else { + session->passkeys().requestList( + ) | rpl::take(1) | rpl::on_next([=] { + showBox(); + }, controller->lifetime()); + } + return Result::Handled; +} + +Result ShowAutoDeleteSetCustom(const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->setHighlightControlId(u"auto-delete/set-custom"_q); + ctx.controller->showSettings(::Settings::GlobalTTLId()); + return Result::Handled; +} + Result ShowNotificationType( const Context &ctx, Data::DefaultNotify type, @@ -249,22 +341,49 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"my-profile/posts"_q, - .action = CodeBlock{ ShowMyProfile }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->setHighlightControlId(u"my-profile/posts"_q); + return ShowMyProfile(ctx); + }}, }); router.add(u"settings"_q, { .path = u"my-profile/posts/add-album"_q, - .action = CodeBlock{ ShowMyProfile }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->setHighlightControlId(u"my-profile/posts/add-album"_q); + return ShowMyProfile(ctx); + }}, }); router.add(u"settings"_q, { .path = u"my-profile/gifts"_q, - .action = CodeBlock{ ShowMyProfile }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->showSection( + Info::PeerGifts::Make(ctx.controller->session().user())); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"my-profile/archived-posts"_q, - .action = CodeBlock{ ShowMyProfile }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->showSection(Info::Stories::Make( + ctx.controller->session().user(), + Info::Stories::ArchiveId())); + return Result::Handled; + }}, }); router.add(u"settings"_q, { @@ -395,12 +514,60 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"privacy/active-websites/disconnect-all"_q, - .action = SettingsSection{ ::Settings::Websites::Id() }, + .action = SettingsControl{ + ::Settings::Websites::Id(), + u"websites/disconnect-all"_q, + }, }); + const auto openPasscode = [](const Context &ctx, const QString &highlight) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + if (!highlight.isEmpty()) { + ctx.controller->setHighlightControlId(highlight); + } + const auto &local = ctx.controller->session().domain().local(); + if (local.hasLocalPasscode()) { + ctx.controller->showSettings(::Settings::LocalPasscodeCheckId()); + } else { + ctx.controller->showSettings(::Settings::LocalPasscodeCreateId()); + } + return Result::Handled; + }; router.add(u"settings"_q, { .path = u"privacy/passcode"_q, - .action = SettingsSection{ ::Settings::LocalPasscodeManageId() }, + .action = CodeBlock{ [=](const Context &ctx) { + return openPasscode(ctx, QString()); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/passcode/disable"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openPasscode(ctx, u"passcode/disable"_q); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/passcode/change"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openPasscode(ctx, u"passcode/change"_q); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/passcode/auto-lock"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openPasscode(ctx, u"passcode/auto-lock"_q); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/passcode/face-id"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openPasscode(ctx, u"passcode/biometrics"_q); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/passcode/fingerprint"_q, + .action = AliasTo{ u"settings"_q, u"privacy/passcode/face-id"_q }, }); router.add(u"settings"_q, { @@ -408,64 +575,67 @@ void RegisterSettingsHandlers(Router &router) { .action = SettingsSection{ ::Settings::GlobalTTLId() }, }); + const auto openCloudPassword = [](const Context &ctx, const QString &highlight) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + if (!highlight.isEmpty()) { + ctx.controller->setHighlightControlId(highlight); + } + const auto state = ctx.controller->session().api().cloudPassword().stateCurrent(); + if (!state) { + ctx.controller->showSettings(::Settings::CloudPasswordStartId()); + } else if (!state->unconfirmedPattern.isEmpty()) { + ctx.controller->showSettings(::Settings::CloudPasswordEmailConfirmId()); + } else if (state->hasPassword) { + ctx.controller->showSettings(::Settings::CloudPasswordInputId()); + } else { + ctx.controller->showSettings(::Settings::CloudPasswordStartId()); + } + return Result::Handled; + }; router.add(u"settings"_q, { .path = u"privacy/2sv"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = CodeBlock{ [=](const Context &ctx) { + return openCloudPassword(ctx, QString()); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/2sv/change"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openCloudPassword(ctx, u"2sv/change"_q); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/2sv/disable"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openCloudPassword(ctx, u"2sv/disable"_q); + }}, + }); + router.add(u"settings"_q, { + .path = u"privacy/2sv/change-email"_q, + .action = CodeBlock{ [=](const Context &ctx) { + return openCloudPassword(ctx, u"2sv/change-email"_q); + }}, }); router.add(u"settings"_q, { .path = u"privacy/passkey"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowPasskeys(ctx, false); + }}, }); router.add(u"settings"_q, { .path = u"privacy/passkey/create"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/passcode/disable"_q, - .action = SettingsSection{ ::Settings::LocalPasscodeManageId() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/passcode/change"_q, - .action = SettingsSection{ ::Settings::LocalPasscodeManageId() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/passcode/auto-lock"_q, - .action = SettingsSection{ ::Settings::LocalPasscodeManageId() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/passcode/face-id"_q, - .action = SettingsSection{ ::Settings::LocalPasscodeManageId() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/passcode/fingerprint"_q, - .action = SettingsSection{ ::Settings::LocalPasscodeManageId() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/2sv/change"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/2sv/disable"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, - }); - - router.add(u"settings"_q, { - .path = u"privacy/2sv/change-email"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowPasskeys(ctx, true); + }}, }); router.add(u"settings"_q, { .path = u"privacy/auto-delete/set-custom"_q, - .action = SettingsSection{ ::Settings::GlobalTTLId() }, + .action = CodeBlock{ ShowAutoDeleteSetCustom }, }); router.add(u"settings"_q, { @@ -925,17 +1095,41 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"privacy/messages"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show(Box(EditMessagesPrivacyBox, ctx.controller, QString())); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"privacy/messages/set-price"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show(Box( + EditMessagesPrivacyBox, + ctx.controller, + u"privacy/set-price"_q)); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"privacy/messages/remove-fee"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show(Box( + EditMessagesPrivacyBox, + ctx.controller, + u"privacy/remove-fee"_q)); + return Result::Handled; + }}, }); router.add(u"settings"_q, { @@ -972,57 +1166,104 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"privacy/self-destruct"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = SettingsControl{ + ::Settings::PrivacySecurity::Id(), + u"privacy/self_destruct"_q, + }, }); router.add(u"settings"_q, { .path = u"privacy/data-settings/suggest-contacts"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = SettingsControl{ + ::Settings::PrivacySecurity::Id(), + u"privacy/top_peers"_q, + }, }); router.add(u"settings"_q, { .path = u"privacy/data-settings/clear-payment-info"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = SettingsControl{ + ::Settings::PrivacySecurity::Id(), + u"privacy/bots_payment"_q, + }, }); router.add(u"settings"_q, { .path = u"privacy/archive-and-mute"_q, - .action = SettingsSection{ ::Settings::PrivacySecurity::Id() }, + .action = SettingsControl{ + ::Settings::PrivacySecurity::Id(), + u"privacy/archive_and_mute"_q, + }, }); router.add(u"settings"_q, { .path = u"data/storage"_q, - .action = SettingsSection{ ::Settings::Advanced::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + LocalStorageBox::Show(ctx.controller); + return Result::Handled; + }}, }); - - router.add(u"settings"_q, { - .path = u"data/proxy"_q, - .action = SettingsSection{ ::Settings::Advanced::Id() }, - }); - router.add(u"settings"_q, { .path = u"data/storage/clear-cache"_q, - .action = SettingsSection{ ::Settings::Advanced::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + LocalStorageBox::Show(ctx.controller, u"storage/clear-cache"_q); + return Result::Handled; + }}, }); - router.add(u"settings"_q, { .path = u"data/max-cache"_q, - .action = SettingsSection{ ::Settings::Advanced::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + LocalStorageBox::Show(ctx.controller, u"storage/max-cache"_q); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"data/show-18-content"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/show-18-content"_q, + }, }); + router.add(u"settings"_q, { + .path = u"data/proxy"_q, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ProxiesBoxController::Show(ctx.controller); + return Result::Handled; + }}, + }); router.add(u"settings"_q, { .path = u"data/proxy/add-proxy"_q, - .action = SettingsSection{ ::Settings::Advanced::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ProxiesBoxController::Show(ctx.controller, u"proxy/add-proxy"_q); + return Result::Handled; + }}, }); - router.add(u"settings"_q, { .path = u"data/proxy/share-list"_q, - .action = SettingsSection{ ::Settings::Advanced::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ProxiesBoxController::Show(ctx.controller, u"proxy/share-list"_q); + return Result::Handled; + }}, }); router.add(u"settings"_q, { @@ -1032,52 +1273,78 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"power-saving"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowPowerSavingBox(ctx); + }}, }); router.add(u"settings"_q, { .path = u"power-saving/stickers"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowPowerSavingBox(ctx, PowerSaving::kStickersPanel); + }}, }); router.add(u"settings"_q, { .path = u"power-saving/emoji"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowPowerSavingBox(ctx, PowerSaving::kEmojiPanel); + }}, }); router.add(u"settings"_q, { .path = u"power-saving/effects"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowPowerSavingBox(ctx, PowerSaving::kChatBackground); + }}, }); router.add(u"settings"_q, { .path = u"appearance/themes"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/themes"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/themes/edit"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/themes-edit"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/themes/create"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/themes-create"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/wallpapers"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/wallpapers"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/wallpapers/set"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/wallpapers-set"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/wallpapers/choose-photo"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/wallpapers-choose-photo"_q, + }, }); router.add(u"settings"_q, { @@ -1122,95 +1389,160 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"appearance/night-mode"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowMainMenuWithHighlight(ctx, u"main-menu/night-mode"_q); + }}, }); router.add(u"settings"_q, { .path = u"appearance/auto-night-mode"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/auto-night-mode"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/text-size"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Main::Id(), + u"main/scale"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/animations"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = AliasTo{ u"settings"_q, u"power-saving"_q }, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/stickers-emoji"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/edit"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show(Box( + ctx.controller->uiShow(), + StickersBox::Section::Installed)); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/trending"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show(Box( + ctx.controller->uiShow(), + StickersBox::Section::Featured)); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/archived"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show(Box( + ctx.controller->uiShow(), + StickersBox::Section::Archived)); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/emoji"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ctx.controller->show( + Box(&ctx.controller->session())); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/emoji/suggest"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/suggest-animated-emoji"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/emoji/quick-reaction"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/quick-reaction"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/emoji/quick-reaction/choose"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/quick-reaction-choose"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/suggest-by-emoji"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/suggest-by-emoji"_q, + }, }); router.add(u"settings"_q, { .path = u"appearance/stickers-and-emoji/emoji/large"_q, - .action = SettingsSection{ ::Settings::Chat::Id() }, + .action = SettingsControl{ + ::Settings::Chat::Id(), + u"chat/large-emoji"_q, + }, }); router.add(u"settings"_q, { .path = u"language"_q, - .action = CodeBlock{ ShowLanguageBox }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowLanguageBox(ctx); + }}, .requiresAuth = false, }); router.add(u"settings"_q, { .path = u"language/show-button"_q, - .action = CodeBlock{ ShowLanguageBox }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowLanguageBox(ctx, u"language/show-button"_q); + }}, .requiresAuth = false, }); router.add(u"settings"_q, { .path = u"language/translate-chats"_q, - .action = CodeBlock{ ShowLanguageBox }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowLanguageBox(ctx, u"language/translate-chats"_q); + }}, .requiresAuth = false, }); router.add(u"settings"_q, { .path = u"language/do-not-translate"_q, - .action = CodeBlock{ ShowLanguageBox }, + .action = CodeBlock{ [](const Context &ctx) { + return ShowLanguageBox(ctx, u"language/do-not-translate"_q); + }}, .requiresAuth = false, }); @@ -1226,31 +1558,51 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"stars/top-up"_q, - .action = SettingsSection{ ::Settings::CreditsId() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + static auto handler = ::Settings::BuyStarsHandler(); + handler.handler(ctx.controller->uiShow())(); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"stars/stats"_q, - .action = SettingsControl{ - ::Settings::CreditsId(), - u"stars/stats"_q, - }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + const auto self = ctx.controller->session().user(); + ctx.controller->showSection(Info::BotEarn::Make(self)); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"stars/gift"_q, - .action = SettingsControl{ - ::Settings::CreditsId(), - u"stars/gift"_q, - }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + Ui::ShowGiftCreditsBox(ctx.controller, nullptr); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"stars/earn"_q, - .action = SettingsControl{ - ::Settings::CreditsId(), - u"stars/earn"_q, - }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + const auto self = ctx.controller->session().user(); + if (Info::BotStarRef::Join::Allowed(self)) { + ctx.controller->showSection(Info::BotStarRef::Join::Make(self)); + } + return Result::Handled; + }}, }); router.add(u"settings"_q, { @@ -1273,10 +1625,13 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"send-gift"_q, - .action = SettingsControl{ - ::Settings::Main::Id(), - u"main/send-gift"_q, - }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + Ui::ChooseStarGiftRecipient(ctx.controller); + return Result::Handled; + }}, }); router.add(u"settings"_q, { @@ -1302,7 +1657,13 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"calls/all"_q, - .action = SettingsSection{ ::Settings::Calls::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + Calls::ShowCallsBox(ctx.controller); + return Result::Handled; + }}, }); router.add(u"settings"_q, { @@ -1313,18 +1674,22 @@ void RegisterSettingsHandlers(Router &router) { router.add(u"settings"_q, { .path = u"ask-question"_q, - .action = SettingsControl{ - ::Settings::Main::Id(), - u"main/ask-question"_q, - }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + ::Settings::OpenAskQuestionConfirm(ctx.controller); + return Result::Handled; + }}, }); router.add(u"settings"_q, { .path = u"features"_q, - .action = SettingsControl{ - ::Settings::Main::Id(), - u"main/features"_q, - }, + .action = CodeBlock{ [](const Context &ctx) { + UrlClickHandler::Open(tr::lng_telegram_features_url(tr::now)); + return Result::Handled; + }}, + .requiresAuth = false, }); router.add(u"settings"_q, { @@ -1415,7 +1780,13 @@ void RegisterSettingsHandlers(Router &router) { // Calls deep links. router.add(u"settings"_q, { .path = u"calls/start-call"_q, - .action = SettingsSection{ ::Settings::Calls::Id() }, + .action = CodeBlock{ [](const Context &ctx) { + if (!ctx.controller) { + return Result::NeedsAuth; + } + Calls::ShowCallsBox(ctx.controller, true); + return Result::Handled; + }}, }); // Devices (sessions) deep links. diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 8b347cb799..176585c919 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -1280,7 +1280,7 @@ bool EditPaidMessagesFee( ShowEditChatPermissions(controller, channel); } } else { - controller->show(Box(EditMessagesPrivacyBox, controller)); + controller->show(Box(EditMessagesPrivacyBox, controller, QString())); } return true; } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp index fc78769c81..9d5222d6eb 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp @@ -104,7 +104,7 @@ Fn FillFilterValueList( not_null container, bool isChannel, const FilterValue &filter) { - auto [checkboxes, getResult, changes] = CreateEditAdminLogFilter( + auto [checkboxes, getResult, changes, highlightWidget] = CreateEditAdminLogFilter( container, filter.flags ? (*filter.flags) : ~FilterValue::Flags(0), isChannel); diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index f9f5b1ae42..8a63bd80b7 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -786,17 +786,25 @@ void WrapWidget::showFinishedHook() { _content->showFinished(); if (_topBarMenuToggle - && _controller->section().type() == Section::Type::Settings - && _controller->section().settingsType() == ::Settings::Main::Id()) { + && _controller->section().type() == Section::Type::Settings) { const auto controller = _controller->parentController(); - const auto logoutId = u"settings/log-out"_q; - if (controller->takeHighlightControlId(logoutId)) { + const auto settingsType = _controller->section().settingsType(); + const auto highlightId = [&]() -> QString { + if (settingsType == ::Settings::Main::Id()) { + return u"settings/log-out"_q; + } else if (settingsType == ::Settings::Chat::Id()) { + return u"chat/themes-create"_q; + } + return QString(); + }(); + if (!highlightId.isEmpty() + && controller->takeHighlightControlId(highlightId)) { showTopBarMenu(false); if (_topBarMenu) { const auto menu = _topBarMenu->menu(); for (const auto action : menu->actions()) { const auto controlId = "highlight-control-id"; - if (action->property(controlId).toString() == logoutId) { + if (action->property(controlId).toString() == highlightId) { if (const auto item = menu->itemForAction(action)) { ::Settings::HighlightWidget(item); } diff --git a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp index 08fbe4ef5e..ead9112378 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp @@ -545,6 +545,29 @@ void InnerWidget::enableBackButton() { void InnerWidget::showFinished() { _showFinished.fire({}); + + const auto window = _controller->parentController(); + const auto id = window->highlightControlId(); + if (id.isEmpty()) { + return; + } + if (id == u"my-profile/posts"_q) { + window->setHighlightControlId(QString()); + if (_albumsWrap) { + ::Settings::HighlightWidget(_albumsWrap); + } + } else if (id == u"my-profile/posts/add-album"_q) { + window->setHighlightControlId(QString()); + if (_albumsWrap) { + ::Settings::HighlightWidget(_albumsWrap); + } + _controller->uiShow()->show(Box( + NewAlbumBox, + _controller, + _peer, + StoryId(), + [=](Data::StoryAlbum album) { albumAdded(album); })); + } } void InnerWidget::finalizeTop() { diff --git a/Telegram/SourceFiles/settings/builder/settings_advanced_builder.cpp b/Telegram/SourceFiles/settings/builder/settings_advanced_builder.cpp index 6005341846..ff01f62c57 100644 --- a/Telegram/SourceFiles/settings/builder/settings_advanced_builder.cpp +++ b/Telegram/SourceFiles/settings/builder/settings_advanced_builder.cpp @@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_chat.h" #include "settings/settings_experimental.h" #include "settings/settings_power_saving.h" +#include "ui/power_saving.h" #include "storage/localstorage.h" #include "storage/storage_domain.h" #include "tray.h" @@ -746,7 +747,7 @@ void BuildPerformanceSection( .st = &st::settingsButtonNoIcon, .onClick = [=] { if (controller) { - controller->window().show(Box(PowerSavingBox)); + controller->window().show(Box(PowerSavingBox, PowerSaving::Flags())); } }, .keywords = { u"power"_q, u"saving"_q, u"battery"_q, u"animation"_q }, diff --git a/Telegram/SourceFiles/settings/builder/settings_builder.cpp b/Telegram/SourceFiles/settings/builder/settings_builder.cpp index 9177665a87..7c41d78a8b 100644 --- a/Telegram/SourceFiles/settings/builder/settings_builder.cpp +++ b/Telegram/SourceFiles/settings/builder/settings_builder.cpp @@ -40,7 +40,8 @@ SectionBuilder::SectionBuilder(BuildContext context) } Ui::RpWidget *SectionBuilder::addControl(ControlArgs &&args) { - return v::match(_context, [&](const WidgetContext &ctx) { + const auto id = args.id; + const auto raw = v::match(_context, [&](const WidgetContext &ctx) { if (!args.factory) { return static_cast(nullptr); } @@ -58,6 +59,10 @@ Ui::RpWidget *SectionBuilder::addControl(ControlArgs &&args) { } return static_cast(nullptr); }); + if (raw && !id.isEmpty()) { + registerHighlight(id, raw, {}); + } + return raw; } Ui::SettingsButton *SectionBuilder::addSettingsButton(ButtonArgs &&args) { @@ -461,6 +466,14 @@ Fn SectionBuilder::showOther() const { }); } +HighlightRegistry *SectionBuilder::highlights() const { + return v::match(_context, [](const WidgetContext &ctx) { + return ctx.highlights; + }, [](const SearchContext &) -> HighlightRegistry* { + return nullptr; + }); +} + void SectionBuilder::registerHighlight( QString id, QWidget *widget, diff --git a/Telegram/SourceFiles/settings/builder/settings_builder.h b/Telegram/SourceFiles/settings/builder/settings_builder.h index dea686411a..8aa1b2c46f 100644 --- a/Telegram/SourceFiles/settings/builder/settings_builder.h +++ b/Telegram/SourceFiles/settings/builder/settings_builder.h @@ -201,6 +201,7 @@ public: [[nodiscard]] Ui::VerticalLayout *container() const; [[nodiscard]] Window::SessionController *controller() const; [[nodiscard]] Fn showOther() const; + [[nodiscard]] HighlightRegistry *highlights() const; private: void registerHighlight( diff --git a/Telegram/SourceFiles/settings/builder/settings_chat_builder.cpp b/Telegram/SourceFiles/settings/builder/settings_chat_builder.cpp index a667c83684..0b006f9cc6 100644 --- a/Telegram/SourceFiles/settings/builder/settings_chat_builder.cpp +++ b/Telegram/SourceFiles/settings/builder/settings_chat_builder.cpp @@ -30,7 +30,8 @@ namespace { void BuildChatSectionContent( SectionBuilder &builder, Window::SessionController *controller, - Fn showOther) { + Fn showOther, + HighlightRegistry *highlights) { if (!controller) { builder.addSettingsButton({ .id = u"appearance/theme"_q, @@ -116,15 +117,15 @@ void BuildChatSectionContent( auto updateOnTick = rpl::single( ) | rpl::then(base::timer_each(60 * crl::time(1000))); - SetupThemeOptions(controller, container); - SetupThemeSettings(controller, container); - SetupCloudThemes(controller, container); - SetupChatBackground(controller, container); + SetupThemeOptions(controller, container, highlights); + SetupThemeSettings(controller, container, highlights); + SetupCloudThemes(controller, container, highlights); + SetupChatBackground(controller, container, highlights); SetupChatListQuickAction(controller, container); - SetupStickersEmoji(controller, container); - SetupMessages(controller, container); + SetupStickersEmoji(controller, container, highlights); + SetupMessages(controller, container, highlights); Ui::AddDivider(container); - SetupSensitiveContent(controller, container, std::move(updateOnTick)); + SetupSensitiveContent(controller, container, std::move(updateOnTick), highlights); SetupArchive(controller, container, showOther); } @@ -146,7 +147,7 @@ void ChatSection( .highlights = highlights, }); - BuildChatSectionContent(builder, controller, showOther); + BuildChatSectionContent(builder, controller, showOther, highlights); std::move(showFinished) | rpl::on_next([=] { for (const auto &[id, entry] : *highlights) { @@ -163,7 +164,7 @@ void ChatSection( std::vector ChatSectionForSearch() { std::vector entries; SectionBuilder builder(SearchContext{ .entries = &entries }); - BuildChatSectionContent(builder, nullptr, nullptr); + BuildChatSectionContent(builder, nullptr, nullptr, nullptr); return entries; } diff --git a/Telegram/SourceFiles/settings/builder/settings_main_builder.cpp b/Telegram/SourceFiles/settings/builder/settings_main_builder.cpp index bdac3f5e10..948d3d7612 100644 --- a/Telegram/SourceFiles/settings/builder/settings_main_builder.cpp +++ b/Telegram/SourceFiles/settings/builder/settings_main_builder.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_main.h" #include "settings/settings_notifications.h" #include "settings/settings_power_saving.h" +#include "ui/power_saving.h" #include "settings/settings_premium.h" #include "settings/settings_privacy_security.h" #include "ui/basic_click_handlers.h" @@ -149,7 +150,7 @@ void BuildSectionButtons( .title = tr::lng_settings_power_menu(), .icon = { &st::menuIconPowerUsage }, .onClick = window - ? Fn([=] { window->show(Box(PowerSavingBox)); }) + ? Fn([=] { window->show(Box(PowerSavingBox, PowerSaving::Flags())); }) : Fn(nullptr), .keywords = { u"battery"_q, u"animations"_q, u"power"_q, u"saving"_q }, }); @@ -298,20 +299,11 @@ void BuildHelpSection( builder.addDivider(); builder.addSkip(); - const auto faqClick = controller - ? [=] { - UrlClickHandler::Open( - tr::lng_settings_faq_link(tr::now), - QVariant::fromValue(ClickHandlerContext{ - .sessionWindow = base::make_weak(controller), - })); - } - : Fn(); builder.addSettingsButton({ .id = u"main/faq"_q, .title = tr::lng_settings_faq(), .icon = { &st::menuIconFaq }, - .onClick = faqClick, + .onClick = [=] { OpenFaq(controller); }, .keywords = { u"help"_q, u"support"_q, u"questions"_q }, }); @@ -329,9 +321,7 @@ void BuildHelpSection( .id = u"main/ask-question"_q, .title = tr::lng_settings_ask_question(), .icon = { &st::menuIconDiscussion }, - .onClick = [] { - UrlClickHandler::Open(tr::lng_telegram_features_url(tr::now)); - }, + .onClick = [=] { OpenAskQuestionConfirm(controller); }, .keywords = { u"contact"_q, u"feedback"_q }, }); diff --git a/Telegram/SourceFiles/settings/builder/settings_privacy_security_builder.cpp b/Telegram/SourceFiles/settings/builder/settings_privacy_security_builder.cpp index 77fa3d29f3..c716667c4d 100644 --- a/Telegram/SourceFiles/settings/builder/settings_privacy_security_builder.cpp +++ b/Telegram/SourceFiles/settings/builder/settings_privacy_security_builder.cpp @@ -395,7 +395,7 @@ void BuildPrivacySection( .st = &st::settingsButtonNoIcon, .label = rpl::duplicate(messagesLabel), .onClick = [=] { - controller->show(Box(EditMessagesPrivacyBox, controller)); + controller->show(Box(EditMessagesPrivacyBox, controller, QString())); }, .keywords = { u"messages"_q, u"new"_q, u"unknown"_q }, }); @@ -466,13 +466,13 @@ void BuildPrivacySection( void BuildArchiveAndMuteSection( SectionBuilder &builder, not_null controller) { - SetupArchiveAndMute(controller, builder.container()); + SetupArchiveAndMute(controller, builder.container(), builder.highlights()); } void BuildBotsAndWebsitesSection( SectionBuilder &builder, not_null controller) { - SetupBotsAndWebsites(controller, builder.container()); + SetupBotsAndWebsites(controller, builder.container(), builder.highlights()); } void BuildTopPeersSection( diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp index e20cc28883..b9917e268b 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp @@ -53,11 +53,11 @@ BottomButton CreateBottomDisableButton( Ui::AddSkip(content); - content->add(object_ptr