/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "settings/settings_experimental.h" #include "data/components/passkeys.h" #include "main/main_session.h" #include "ui/boxes/confirm_box.h" #include "ui/text/text_entity.h" #include "ui/widgets/menu/menu_add_action_callback.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/slide_wrap.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/vertical_list.h" #include "ui/gl/gl_detection.h" #include "ui/chat/chat_style_radius.h" #include "ui/controls/compose_ai_button_factory.h" #include "base/options.h" #include "boxes/moderate_messages_box.h" #include "core/application.h" #include "core/launcher.h" #include "core/sandbox.h" #include "chat_helpers/tabbed_panel.h" #include "dialogs/dialogs_widget.h" #include "dialogs/ui/dialogs_layout.h" #include "history/history_item_components.h" #include "info/profile/info_profile_actions.h" #include "lang/lang_keys.h" #include "mainwindow.h" #include "mainwidget.h" #include "media/player/media_player_instance.h" #include "mtproto/session_private.h" #include "webview/webview_embed.h" #include "window/main_window.h" #include "window/window_peer_menu.h" #include "window/window_session_controller.h" #include "window/window_controller.h" #include "window/notifications_manager.h" #include "info/info_flexible_scroll.h" #include "chat_helpers/stickers_list_widget.h" #include "styles/style_settings.h" #include "styles/style_layers.h" #include "styles/style_menu_icons.h" #include #include // AyuGram includes #include "ayu/ui/settings/settings_main.h" #include "settings/settings_builder.h" namespace Settings { namespace { const auto kOptionsClipboardPrefix = u"tdesktop-flags:"_q; struct DecodeOptionsResult { bool ok = false; QString json; }; struct ResolvedReferrer { QString controlId; Type section = AyuMain::Id(); }; [[nodiscard]] QString EncodeOptionsToText(const QString &json) { const auto flags = QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals; return kOptionsClipboardPrefix + qs(qCompress(json.toLatin1(), 9).toBase64(flags)); } [[nodiscard]] DecodeOptionsResult DecodeOptionsFromText(const QString &text) { auto result = DecodeOptionsResult(); if (!text.startsWith(kOptionsClipboardPrefix)) { return result; } auto encoded = QStringView(text).mid( kOptionsClipboardPrefix.size()).toLatin1(); const auto compressed = QByteArray::fromBase64Encoding( std::move(encoded), QByteArray::Base64UrlEncoding | QByteArray::AbortOnBase64DecodingErrors); if (!compressed || (*compressed).isEmpty()) { return result; } const auto decoded = qUncompress(*compressed); if (decoded.isEmpty()) { return result; } auto error = QJsonParseError(); const auto parsed = QJsonDocument::fromJson(decoded, &error); if ((error.error != QJsonParseError::NoError) || !parsed.isObject()) { return result; } result.ok = true; result.json = QString::fromUtf8(decoded); return result; } [[nodiscard]] ResolvedReferrer ResolveReferrer( const QString &controlId, not_null session) { const auto ®istry = Builder::SearchRegistry::Instance(); const auto entries = registry.collectAll(session); for (const auto &entry : entries) { if (!entry.section) { continue; } if (entry.id == controlId) { return { .controlId = entry.id, .section = entry.section, }; } if (entry.altIds.contains(controlId)) { return { .controlId = entry.id, .section = entry.section, }; } } return { .controlId = controlId, }; } [[nodiscard]] QString OptionReferrer(const base::options::option &option) { const auto &id = option.id(); if (id == u"tabbed-panel-show-on-click"_q) { return u"ayu/showEmojiPopup"_q; } else if (id == u"show-peer-id-below-about"_q) { return u"ayu/showPeerId"_q; } else if (id == u"use-small-msg-bubble-radius"_q) { return u"ayu/messageBubbleRadius"_q; } else if (id == u"unlimited-recent-stickers"_q) { return u"ayu/recentStickersCount"_q; } else if (id == u"hide-ai-button"_q) { return u"ayu/showAiEditorButtonInMessageField"_q; } return QString(); } void AddOption( not_null window, not_null controller, not_null container, base::options::option &option, rpl::producer<> resetClicks, rpl::producer<> reloadOptionsRequests) { auto &lifetime = container->lifetime(); const auto name = option.name().isEmpty() ? option.id() : option.name(); const auto toggles = lifetime.make_state>(); std::move( resetClicks ) | rpl::map_to( option.defaultValue() ) | rpl::start_to_stream(*toggles, lifetime); std::move(reloadOptionsRequests) | rpl::on_next([=, &option] { toggles->fire_copy(option.value()); }, lifetime); const auto referrer = OptionReferrer(option); Button *button = nullptr; if (!referrer.isEmpty()) { button = container->add(object_ptr