diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 022602562..f0bafb1b1 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -195,6 +195,8 @@ PRIVATE api/api_common.h api/api_editing.cpp api/api_editing.h + api/api_global_privacy.cpp + api/api_global_privacy.h api/api_hash.cpp api/api_hash.h api/api_media.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index e54cbb6ff..22e116eaf 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -424,6 +424,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_passcode_title" = "Local passcode"; "lng_settings_password_title" = "Two-step verification"; "lng_settings_sessions_title" = "Active sessions"; +"lng_settings_new_unknown" = "New chats from unknown users"; +"lng_settings_auto_archive" = "Archive and Mute"; +"lng_settings_auto_archive_about" = "Automatically archive and mute new chats, groups and channels from non-contacts."; "lng_settings_destroy_title" = "Delete my account"; "lng_settings_network_proxy" = "Network and proxy"; "lng_settings_version_info" = "Version and updates"; diff --git a/Telegram/SourceFiles/api/api_global_privacy.cpp b/Telegram/SourceFiles/api/api_global_privacy.cpp new file mode 100644 index 000000000..88fee6de5 --- /dev/null +++ b/Telegram/SourceFiles/api/api_global_privacy.cpp @@ -0,0 +1,94 @@ +/* +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 "api/api_global_privacy.h" + +#include "apiwrap.h" +#include "main/main_session.h" +#include "main/main_account.h" +#include "main/main_app_config.h" + +namespace Api { + +GlobalPrivacy::GlobalPrivacy(not_null api) +: _session(&api->session()) +, _api(&api->instance()) { +} + +void GlobalPrivacy::reload() { + if (_requestId) { + return; + } + _requestId = _api.request(MTPaccount_GetGlobalPrivacySettings( + )).done([=](const MTPGlobalPrivacySettings &result) { + _requestId = 0; + apply(result); + }).fail([=](const RPCError &error) { + _requestId = 0; + }).send(); + + _session->account().appConfig().value( + ) | rpl::start_with_next([=] { + _showArchiveAndMute = _session->account().appConfig().get( + u"autoarchive_setting_available"_q, + false); + }, _session->lifetime()); +} + +bool GlobalPrivacy::archiveAndMuteCurrent() const { + return _archiveAndMute.current(); +} + +rpl::producer GlobalPrivacy::archiveAndMute() const { + return _archiveAndMute.value(); +} + +rpl::producer GlobalPrivacy::showArchiveAndMute() const { + using namespace rpl::mappers; + + return rpl::combine( + archiveAndMute(), + _showArchiveAndMute.value(), + _1 || _2); +} + +rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const { + return _session->account().appConfig().suggestionRequested( + u"AUTOARCHIVE_POPULAR"_q); +} + +void GlobalPrivacy::dismissArchiveAndMuteSuggestion() { + _session->account().appConfig().dismissSuggestion( + u"AUTOARCHIVE_POPULAR"_q); +} + +void GlobalPrivacy::update(bool archiveAndMute) { + using Flag = MTPDglobalPrivacySettings::Flag; + + _api.request(_requestId).cancel(); + _requestId = _api.request(MTPaccount_SetGlobalPrivacySettings( + MTP_globalPrivacySettings( + MTP_flags(Flag::f_archive_and_mute_new_noncontact_peers), + MTP_bool(archiveAndMute)) + )).done([=](const MTPGlobalPrivacySettings &result) { + _requestId = 0; + apply(result); + }).fail([=](const RPCError &error) { + _requestId = 0; + }).send(); + _archiveAndMute = archiveAndMute; +} + +void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) { + data.match([&](const MTPDglobalPrivacySettings &data) { + _archiveAndMute = data.varchive_and_mute_new_noncontact_peers() + ? mtpIsTrue(*data.varchive_and_mute_new_noncontact_peers()) + : false; + }); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_global_privacy.h b/Telegram/SourceFiles/api/api_global_privacy.h new file mode 100644 index 000000000..e35f76cb6 --- /dev/null +++ b/Telegram/SourceFiles/api/api_global_privacy.h @@ -0,0 +1,44 @@ +/* +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 +*/ +#pragma once + +#include "mtproto/sender.h" + +class ApiWrap; + +namespace Main { +class Session; +} // namespace Main + +namespace Api { + +class GlobalPrivacy final { +public: + explicit GlobalPrivacy(not_null api); + + void reload(); + void update(bool archiveAndMute); + + [[nodiscard]] bool archiveAndMuteCurrent() const; + [[nodiscard]] rpl::producer archiveAndMute() const; + [[nodiscard]] rpl::producer showArchiveAndMute() const; + [[nodiscard]] rpl::producer<> suggestArchiveAndMute() const; + void dismissArchiveAndMuteSuggestion(); + +private: + void apply(const MTPGlobalPrivacySettings &data); + + const not_null _session; + MTP::Sender _api; + mtpRequestId _requestId = 0; + rpl::variable _archiveAndMute = false; + rpl::variable _showArchiveAndMute = false; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index f4376e9bb..235d0475d 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_text_entities.h" #include "api/api_self_destruct.h" #include "api/api_sensitive_content.h" +#include "api/api_global_privacy.h" #include "api/api_updates.h" #include "data/stickers/data_stickers.h" #include "data/data_drafts.h" @@ -186,7 +187,8 @@ ApiWrap::ApiWrap(not_null session) , _topPromotionTimer([=] { refreshTopPromotion(); }) , _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); }) , _selfDestruct(std::make_unique(this)) -, _sensitiveContent(std::make_unique(this)) { +, _sensitiveContent(std::make_unique(this)) +, _globalPrivacy(std::make_unique(this)) { crl::on_main(session, [=] { // You can't use _session->lifetime() in the constructor, // only queued, because it is not constructed yet. @@ -5241,6 +5243,10 @@ Api::SensitiveContent &ApiWrap::sensitiveContent() { return *_sensitiveContent; } +Api::GlobalPrivacy &ApiWrap::globalPrivacy() { + return *_globalPrivacy; +} + void ApiWrap::createPoll( const PollData &data, const SendAction &action, diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index ef69df281..27c503176 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -50,6 +50,12 @@ struct CloudPasswordState; } // namespace Core namespace Api { + +class Updates; +class SelfDestruct; +class SensitiveContent; +class GlobalPrivacy; + namespace details { inline QString ToString(const QString &value) { @@ -66,8 +72,6 @@ inline QString ToString(uint64 value) { } // namespace details -class Updates; - template < typename ...Types, typename = std::enable_if_t<(sizeof...(Types) > 0)>> @@ -86,9 +90,6 @@ QString RequestKey(Types &&...values) { return result; } -class SelfDestruct; -class SensitiveContent; - } // namespace Api class ApiWrap : public MTP::Sender, private base::Subscriber { @@ -460,6 +461,7 @@ public: [[nodiscard]] Api::SelfDestruct &selfDestruct(); [[nodiscard]] Api::SensitiveContent &sensitiveContent(); + [[nodiscard]] Api::GlobalPrivacy &globalPrivacy(); void createPoll( const PollData &data, @@ -821,6 +823,7 @@ private: const std::unique_ptr _selfDestruct; const std::unique_ptr _sensitiveContent; + const std::unique_ptr _globalPrivacy; base::flat_map _pollVotesRequestIds; base::flat_map _pollCloseRequestIds; diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index 077c97e0a..bf6648a9a 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -67,6 +67,10 @@ rpl::producer<> AppConfig::refreshed() const { return _refreshed.events(); } +rpl::producer<> AppConfig::value() const { + return _refreshed.events_starting_with({}); +} + template auto AppConfig::getValue(const QString &key, Extractor &&extractor) const { const auto i = _data.find(key); @@ -126,4 +130,29 @@ std::vector AppConfig::getStringArray( }); } +bool AppConfig::suggestionCurrent(const QString &key) const { + return !_dismissedSuggestions.contains(key) + && ranges::contains( + get>( + u"pending_suggestions"_q, + std::vector()), + key); +} + +rpl::producer<> AppConfig::suggestionRequested(const QString &key) const { + return value( + ) | rpl::filter([=] { + return suggestionCurrent(key); + }); +} + +void AppConfig::dismissSuggestion(const QString &key) { + if (!_dismissedSuggestions.emplace(key).second) { + return; + } + _api->request(MTPhelp_DismissSuggestion( + MTP_string(key) + )).send(); +} + } // namespace Main diff --git a/Telegram/SourceFiles/main/main_app_config.h b/Telegram/SourceFiles/main/main_app_config.h index 0ab3625a3..176d73c58 100644 --- a/Telegram/SourceFiles/main/main_app_config.h +++ b/Telegram/SourceFiles/main/main_app_config.h @@ -31,6 +31,12 @@ public: } [[nodiscard]] rpl::producer<> refreshed() const; + [[nodiscard]] rpl::producer<> value() const; + + [[nodiscard]] bool suggestionCurrent(const QString &key) const; + [[nodiscard]] rpl::producer<> suggestionRequested( + const QString &key) const; + void dismissSuggestion(const QString &key); void refresh(); @@ -60,6 +66,7 @@ private: mtpRequestId _requestId = 0; base::flat_map _data; rpl::event_stream<> _refreshed; + base::flat_set _dismissedSuggestions; rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index 4c259ec2f..7c64f46c0 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -30,6 +30,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_account.h" #include "main/main_app_config.h" #include "apiwrap.h" +#include "api/api_sensitive_content.h" +#include "api/api_global_privacy.h" #include "window/window_session_controller.h" #include "core/file_utilities.h" #include "base/call_delayed.h" @@ -373,6 +375,8 @@ void Main::setupContent(not_null controller) { // If we load this in advance it won't jump when we open its' section. controller->session().api().reloadPasswordState(); controller->session().api().reloadContactSignupSilent(); + controller->session().api().sensitiveContent().reload(); + controller->session().api().globalPrivacy().reload(); controller->session().data().cloudThemes().refresh(); } diff --git a/Telegram/SourceFiles/settings/settings_privacy_security.cpp b/Telegram/SourceFiles/settings/settings_privacy_security.cpp index 58fcfd88b..06e25d64b 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_security.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_security.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_self_destruct.h" #include "api/api_sensitive_content.h" +#include "api/api_global_privacy.h" #include "settings/settings_common.h" #include "settings/settings_privacy_controllers.h" #include "boxes/peer_list_box.h" @@ -186,6 +187,49 @@ void SetupPrivacy( AddDividerText(container, tr::lng_settings_group_privacy_about()); } +void SetupArchiveAndMute( + not_null controller, + not_null container) { + using namespace rpl::mappers; + + const auto wrap = container->add( + object_ptr>( + container, + object_ptr(container))); + const auto inner = wrap->entity(); + + AddSkip(inner); + AddSubsectionTitle(inner, tr::lng_settings_new_unknown()); + + const auto session = &controller->session(); + + const auto privacy = &session->api().globalPrivacy(); + privacy->reload(); + AddButton( + inner, + tr::lng_settings_auto_archive(), + st::settingsButton + )->toggleOn( + privacy->archiveAndMute() + )->toggledChanges( + ) | rpl::filter([=](bool toggled) { + return toggled != privacy->archiveAndMuteCurrent(); + }) | rpl::start_with_next([=](bool toggled) { + privacy->update(toggled); + }, container->lifetime()); + + AddSkip(inner); + AddDividerText(inner, tr::lng_settings_auto_archive_about()); + + using namespace rpl::mappers; + wrap->toggleOn(rpl::single( + false + ) | rpl::then( + session->api().globalPrivacy().showArchiveAndMute( + ) | rpl::filter(_1) | rpl::take(1) + )); +} + not_null*> AddSeparator( not_null container) { return container->add( @@ -647,6 +691,7 @@ void PrivacySecurity::setupContent( const auto content = Ui::CreateChild(this); SetupPrivacy(controller, content); + SetupArchiveAndMute(controller, content); SetupSessionsList(controller, content); SetupLocalPasscode(controller, content); SetupCloudPassword(controller, content);