/* 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_privacy_security.h" #include "api/api_authorizations.h" #include "api/api_cloud_password.h" #include "api/api_self_destruct.h" #include "api/api_sensitive_content.h" #include "api/api_global_privacy.h" #include "api/api_websites.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 "settings/settings_blocked_peers.h" #include "settings/settings_global_ttl.h" #include "settings/settings_local_passcode.h" #include "settings/settings_premium.h" // Settings::ShowPremium. #include "settings/settings_privacy_controllers.h" #include "settings/settings_websites.h" #include "base/timer_rpl.h" #include "boxes/passcode_box.h" #include "boxes/sessions_box.h" #include "ui/boxes/confirm_box.h" #include "boxes/self_destruction_box.h" #include "core/application.h" #include "core/core_settings.h" #include "ui/chat/chat_style.h" #include "ui/effects/premium_top_bar.h" #include "ui/text/format_values.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/fade_wrap.h" #include "ui/widgets/fields/input_field.h" #include "ui/widgets/shadow.h" #include "ui/widgets/checkbox.h" #include "ui/vertical_list.h" #include "ui/rect.h" #include "calls/calls_instance.h" #include "core/update_checker.h" #include "lang/lang_keys.h" #include "data/components/top_peers.h" #include "data/data_session.h" #include "data/data_chat.h" #include "data/data_channel.h" #include "data/data_peer_values.h" #include "main/main_app_config.h" #include "main/main_domain.h" #include "main/main_session.h" #include "storage/storage_domain.h" #include "window/window_session_controller.h" #include "apiwrap.h" #include "styles/style_settings.h" #include "styles/style_menu_icons.h" #include "styles/style_layers.h" #include #include namespace Settings { namespace { constexpr auto kUpdateTimeout = 60 * crl::time(1000); using Privacy = Api::UserPrivacy; [[nodiscard]] QImage PremiumStar() { const auto factor = style::DevicePixelRatio(); const auto size = Size(st::settingsButtonNoIcon.style.font->ascent); auto image = QImage( size * factor, QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(factor); image.fill(Qt::transparent); { auto p = QPainter(&image); auto star = QSvgRenderer(Ui::Premium::ColorizedSvg()); star.render(&p, Rect(size)); } return image; } void AddPremiumStar( not_null button, not_null session, rpl::producer label, const QMargins &padding) { const auto badge = Ui::CreateChild(button.get()); badge->showOn(Data::AmPremiumValue(session)); const auto sampleLeft = st::settingsColorSamplePadding.left(); const auto badgeLeft = padding.left() + sampleLeft; auto star = PremiumStar(); badge->resize(star.size() / style::DevicePixelRatio()); badge->paintRequest( ) | rpl::start_with_next([=] { auto p = QPainter(badge); p.drawImage(0, 0, star); }, badge->lifetime()); rpl::combine( button->sizeValue(), std::move(label) ) | rpl::start_with_next([=](const QSize &s, const QString &) { if (s.isNull()) { return; } badge->moveToLeft( button->fullTextWidth() + badgeLeft, (s.height() - badge->height()) / 2); }, badge->lifetime()); } void OpenFileConfirmationsBox(not_null box) { box->setTitle(tr::lng_settings_file_confirmations()); const auto settings = &Core::App().settings(); const auto &list = settings->noWarningExtensions(); const auto text = QStringList(begin(list), end(list)).join(' '); const auto layout = box->verticalLayout(); const auto extensions = box->addRow( object_ptr( box, st::defaultInputField, Ui::InputField::Mode::MultiLine, tr::lng_settings_edit_extensions(), TextWithTags{ text }), st::boxRowPadding + QMargins(0, 0, 0, st::settingsPrivacySkip)); Ui::AddDividerText(layout, tr::lng_settings_edit_extensions_about()); Ui::AddSkip(layout); const auto ip = layout->add(object_ptr( box, tr::lng_settings_edit_ip_confirm(), st::settingsButtonNoIcon ))->toggleOn(rpl::single(settings->ipRevealWarning())); Ui::AddSkip(layout); Ui::AddDividerText(layout, tr::lng_settings_edit_ip_confirm_about()); box->setFocusCallback([=] { extensions->setFocusFast(); }); box->addButton(tr::lng_settings_save(), [=] { const auto extensionsList = extensions->getLastText() .mid(0, 10240) .split(' ', Qt::SkipEmptyParts) .mid(0, 1024); auto extensions = base::flat_set( extensionsList.begin(), extensionsList.end()); const auto ipRevealWarning = ip->toggled(); if (extensions != settings->noWarningExtensions() || ipRevealWarning != settings->ipRevealWarning()) { settings->setNoWarningExtensions(std::move(extensions)); settings->setIpRevealWarning(ipRevealWarning); Core::App().saveSettingsDelayed(); } box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); } QString PrivacyBase(Privacy::Key key, const Privacy::Rule &rule) { using Key = Privacy::Key; using Option = Privacy::Option; switch (key) { case Key::CallsPeer2Peer: switch (rule.option) { case Option::Everyone: return tr::lng_edit_privacy_calls_p2p_everyone(tr::now); case Option::Contacts: return tr::lng_edit_privacy_calls_p2p_contacts(tr::now); case Option::Nobody: return tr::lng_edit_privacy_calls_p2p_nobody(tr::now); } [[fallthrough]]; default: switch (rule.option) { case Option::Everyone: return tr::lng_edit_privacy_everyone(tr::now); case Option::Contacts: return rule.always.premiums ? tr::lng_edit_privacy_contacts_and_premium(tr::now) : tr::lng_edit_privacy_contacts(tr::now); case Option::CloseFriends: return tr::lng_edit_privacy_close_friends(tr::now); case Option::Nobody: return rule.always.premiums ? tr::lng_edit_privacy_premium(tr::now) : tr::lng_edit_privacy_nobody(tr::now); } Unexpected("Value in Privacy::Option."); } } rpl::producer PrivacyString( not_null<::Main::Session*> session, Privacy::Key key) { session->api().userPrivacy().reload(key); return session->api().userPrivacy().value( key ) | rpl::map([=](const Privacy::Rule &value) { auto add = QStringList(); if (const auto never = ExceptionUsersCount(value.never.peers)) { add.push_back("-" + QString::number(never)); } if (const auto always = ExceptionUsersCount(value.always.peers)) { add.push_back("+" + QString::number(always)); } if (!add.isEmpty()) { return PrivacyBase(key, value) + " (" + add.join(", ") + ")"; } else { return PrivacyBase(key, value); } }); } #if 0 // Dead code. void AddPremiumPrivacyButton( not_null controller, not_null container, rpl::producer label, Privacy::Key key, Fn()> controllerFactory) { const auto shower = Ui::CreateChild(container.get()); const auto session = &controller->session(); const auto &st = st::settingsButtonNoIcon; const auto button = container->add(object_ptr