diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 074b281e74..c02f644040 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -147,6 +147,16 @@ ApiWrap::MessageToSend::MessageToSend(not_null history) : history(history) { } +MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) { + switch (key) { + case Privacy::Key::Calls: return MTP_inputPrivacyKeyPhoneCall(); + case Privacy::Key::Invites: return MTP_inputPrivacyKeyChatInvite(); + case Privacy::Key::LastSeen: + return MTP_inputPrivacyKeyStatusTimestamp(); + } + Unexpected("Key in ApiWrap::Privacy::Input."); +} + ApiWrap::ApiWrap(not_null session) : _session(session) , _messageDataResolveDelayed([=] { resolveMessageDatas(); }) @@ -1880,112 +1890,139 @@ void ApiWrap::saveDraftToCloudDelayed(not_null history) { } void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector &&rules) { - auto keyTypeId = key.type(); - auto it = _privacySaveRequests.find(keyTypeId); + const auto keyTypeId = key.type(); + const auto it = _privacySaveRequests.find(keyTypeId); if (it != _privacySaveRequests.cend()) { request(it->second).cancel(); _privacySaveRequests.erase(it); } - auto requestId = request(MTPaccount_SetPrivacy(key, MTP_vector(std::move(rules)))).done([this, keyTypeId](const MTPaccount_PrivacyRules &result) { + const auto requestId = request(MTPaccount_SetPrivacy( + key, + MTP_vector(std::move(rules)) + )).done([=](const MTPaccount_PrivacyRules &result) { Expects(result.type() == mtpc_account_privacyRules); auto &rules = result.c_account_privacyRules(); App::feedUsers(rules.vusers); _privacySaveRequests.remove(keyTypeId); handlePrivacyChange(keyTypeId, rules.vrules); - }).fail([this, keyTypeId](const RPCError &error) { + }).fail([=](const RPCError &error) { _privacySaveRequests.remove(keyTypeId); }).send(); _privacySaveRequests.emplace(keyTypeId, requestId); } -void ApiWrap::handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector &rules) { - if (keyTypeId == mtpc_privacyKeyStatusTimestamp) { - enum class Rule { - Unknown, - Allow, - Disallow, - }; - auto userRules = QMap(); - auto contactsRule = Rule::Unknown; - auto everyoneRule = Rule::Unknown; - for (auto &rule : rules.v) { - auto type = rule.type(); - if (type != mtpc_privacyValueAllowAll && type != mtpc_privacyValueDisallowAll && contactsRule != Rule::Unknown) { - // This is simplified: we ignore per-user rules that come after a contacts rule. - // But none of the official apps provide such complicated rule sets, so its fine. - continue; - } - - switch (type) { - case mtpc_privacyValueAllowAll: everyoneRule = Rule::Allow; break; - case mtpc_privacyValueDisallowAll: everyoneRule = Rule::Disallow; break; - case mtpc_privacyValueAllowContacts: contactsRule = Rule::Allow; break; - case mtpc_privacyValueDisallowContacts: contactsRule = Rule::Disallow; break; - case mtpc_privacyValueAllowUsers: { - for_const (auto &userId, rule.c_privacyValueAllowUsers().vusers.v) { - if (!userRules.contains(userId.v)) { - userRules.insert(userId.v, Rule::Allow); - } - } - } break; - case mtpc_privacyValueDisallowUsers: { - for_const (auto &userId, rule.c_privacyValueDisallowUsers().vusers.v) { - if (!userRules.contains(userId.v)) { - userRules.insert(userId.v, Rule::Disallow); - } - } - } break; - } - if (everyoneRule != Rule::Unknown) { - break; - } +void ApiWrap::handlePrivacyChange( + mtpTypeId keyTypeId, + const MTPVector &rules) { + using Key = Privacy::Key; + const auto key = [&]() -> base::optional { + switch (keyTypeId) { + case mtpc_privacyKeyStatusTimestamp: + case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen; + case mtpc_privacyKeyChatInvite: + case mtpc_inputPrivacyKeyChatInvite: return Key::Invites; + case mtpc_privacyKeyPhoneCall: + case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls; } - - auto now = unixtime(); - App::enumerateUsers([&](UserData *user) { - if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) { - return; - } - if (user->onlineTill <= 0) { - return; - } - - if (user->onlineTill + 3 * 86400 >= now) { - user->onlineTill = -2; // recently - } else if (user->onlineTill + 7 * 86400 >= now) { - user->onlineTill = -3; // last week - } else if (user->onlineTill + 30 * 86400 >= now) { - user->onlineTill = -4; // last month - } else { - user->onlineTill = 0; - } - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); - }); - - if (_contactsStatusesRequestId) { - request(_contactsStatusesRequestId).cancel(); - } - _contactsStatusesRequestId = request(MTPcontacts_GetStatuses()).done([this](const MTPVector &result) { - _contactsStatusesRequestId = 0; - for_const (auto &item, result.v) { - Assert(item.type() == mtpc_contactStatus); - auto &data = item.c_contactStatus(); - if (auto user = App::userLoaded(data.vuser_id.v)) { - auto oldOnlineTill = user->onlineTill; - auto newOnlineTill = onlineTillFromStatus(data.vstatus, oldOnlineTill); - if (oldOnlineTill != newOnlineTill) { - user->onlineTill = newOnlineTill; - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); - } - } - } - }).fail([this](const RPCError &error) { - _contactsStatusesRequestId = 0; - }).send(); + return base::none; + }(); + if (!key) { + return; } + pushPrivacy(*key, rules.v); + if (*key == Key::LastSeen) { + updatePrivacyLastSeens(rules.v); + } +} + +void ApiWrap::updatePrivacyLastSeens(const QVector &rules) { + enum class Rule { + Unknown, + Allow, + Disallow, + }; + auto userRules = QMap(); + auto contactsRule = Rule::Unknown; + auto everyoneRule = Rule::Unknown; + for (auto &rule : rules) { + auto type = rule.type(); + if (type != mtpc_privacyValueAllowAll + && type != mtpc_privacyValueDisallowAll + && contactsRule != Rule::Unknown) { + // This is simplified: we ignore per-user rules that come after a contacts rule. + // But none of the official apps provide such complicated rule sets, so its fine. + continue; + } + + switch (type) { + case mtpc_privacyValueAllowAll: everyoneRule = Rule::Allow; break; + case mtpc_privacyValueDisallowAll: everyoneRule = Rule::Disallow; break; + case mtpc_privacyValueAllowContacts: contactsRule = Rule::Allow; break; + case mtpc_privacyValueDisallowContacts: contactsRule = Rule::Disallow; break; + case mtpc_privacyValueAllowUsers: { + for_const (auto &userId, rule.c_privacyValueAllowUsers().vusers.v) { + if (!userRules.contains(userId.v)) { + userRules.insert(userId.v, Rule::Allow); + } + } + } break; + case mtpc_privacyValueDisallowUsers: { + for_const (auto &userId, rule.c_privacyValueDisallowUsers().vusers.v) { + if (!userRules.contains(userId.v)) { + userRules.insert(userId.v, Rule::Disallow); + } + } + } break; + } + if (everyoneRule != Rule::Unknown) { + break; + } + } + + auto now = unixtime(); + App::enumerateUsers([&](UserData *user) { + if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) { + return; + } + if (user->onlineTill <= 0) { + return; + } + + if (user->onlineTill + 3 * 86400 >= now) { + user->onlineTill = -2; // recently + } else if (user->onlineTill + 7 * 86400 >= now) { + user->onlineTill = -3; // last week + } else if (user->onlineTill + 30 * 86400 >= now) { + user->onlineTill = -4; // last month + } else { + user->onlineTill = 0; + } + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); + }); + + if (_contactsStatusesRequestId) { + request(_contactsStatusesRequestId).cancel(); + } + _contactsStatusesRequestId = request(MTPcontacts_GetStatuses()).done([this](const MTPVector &result) { + _contactsStatusesRequestId = 0; + for_const (auto &item, result.v) { + Assert(item.type() == mtpc_contactStatus); + auto &data = item.c_contactStatus(); + if (auto user = App::userLoaded(data.vuser_id.v)) { + auto oldOnlineTill = user->onlineTill; + auto newOnlineTill = onlineTillFromStatus(data.vstatus, oldOnlineTill); + if (oldOnlineTill != newOnlineTill) { + user->onlineTill = newOnlineTill; + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); + } + } + } + }).fail([this](const RPCError &error) { + _contactsStatusesRequestId = 0; + }).send(); } int ApiWrap::onlineTillFromStatus(const MTPUserStatus &status, int currentOnlineTill) { @@ -4977,6 +5014,95 @@ void ApiWrap::saveSelfBio(const QString &text, FnMut done) { }).send(); } +void ApiWrap::reloadPrivacy(Privacy::Key key) { + if (_privacyRequestIds.contains(key)) { + return; + } + const auto requestId = request(MTPaccount_GetPrivacy( + Privacy::Input(key) + )).done([=](const MTPaccount_PrivacyRules &result) { + _privacyRequestIds.erase(key); + result.match([&](const MTPDaccount_privacyRules &data) { + App::feedUsers(data.vusers); + pushPrivacy(key, data.vrules.v); + }); + }).fail([=](const RPCError &error) { + _privacyRequestIds.erase(key); + }).send(); +} + +auto ApiWrap::parsePrivacy(const QVector &rules) +-> Privacy { + using Option = Privacy::Option; + + // This is simplified version of privacy rules interpretation. + // But it should be fine for all the apps + // that use the same subset of features. + auto result = Privacy(); + auto optionSet = false; + const auto SetOption = [&](Option option) { + if (optionSet) return; + optionSet = true; + result.option = option; + }; + auto &always = result.always; + auto &never = result.never; + const auto Feed = [&](const MTPPrivacyRule &rule) { + rule.match([&](const MTPDprivacyValueAllowAll &) { + SetOption(Option::Everyone); + }, [&](const MTPDprivacyValueAllowContacts &) { + SetOption(Option::Contacts); + }, [&](const MTPDprivacyValueAllowUsers &data) { + const auto &users = data.vusers.v; + always.reserve(always.size() + users.size()); + for (const auto userId : users) { + const auto user = App::user(UserId(userId.v)); + if (!base::contains(never, user) + && !base::contains(always, user)) { + always.push_back(user); + } + } + }, [&](const MTPDprivacyValueDisallowContacts &) { + // not supported + }, [&](const MTPDprivacyValueDisallowAll &) { + SetOption(Option::Nobody); + }, [&](const MTPDprivacyValueDisallowUsers &data) { + const auto &users = data.vusers.v; + never.reserve(never.size() + users.size()); + for (const auto userId : users) { + const auto user = App::user(UserId(userId.v)); + if (!base::contains(always, user) + && !base::contains(never, user)) { + never.push_back(user); + } + } + }); + }; + for (const auto &rule : rules) { + Feed(rule); + } + Feed(MTP_privacyValueDisallowAll()); // disallow by default. + return result; +} + +void ApiWrap::pushPrivacy( + Privacy::Key key, + const QVector &rules) { + const auto &saved = (_privacyValues[key] = parsePrivacy(rules)); + const auto i = _privacyChanges.find(key); + if (i != end(_privacyChanges)) { + i->second.fire_copy(saved); + } +} + +auto ApiWrap::privacyValue(Privacy::Key key) -> rpl::producer { + if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) { + return _privacyChanges[key].events_starting_with_copy(i->second); + } else { + return _privacyChanges[key].events(); + } +} + void ApiWrap::readServerHistory(not_null history) { if (history->unreadCount()) { readServerHistoryForce(history); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index ab3f31d132..7d4e9c95bf 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -338,6 +338,26 @@ public: void saveSelfBio(const QString &text, FnMut done); + struct Privacy { + enum class Key { + LastSeen, + Calls, + Invites, + }; + enum class Option { + Everyone, + Contacts, + Nobody, + }; + Option option = Option::Everyone; + std::vector> always; + std::vector> never; + + static MTPInputPrivacyKey Input(Key key); + }; + void reloadPrivacy(Privacy::Key key); + rpl::producer privacyValue(Privacy::Key key); + ~ApiWrap(); private: @@ -521,6 +541,12 @@ private: void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file); + Privacy parsePrivacy(const QVector &rules); + void pushPrivacy( + Privacy::Key key, + const QVector &rules); + void updatePrivacyLastSeens(const QVector &rules); + not_null _session; MessageDataRequests _messageDataRequests; @@ -678,4 +704,8 @@ private: FnMut _saveBioDone; QString _saveBioText; + base::flat_map _privacyRequestIds; + base::flat_map _privacyValues; + std::map> _privacyChanges; + }; diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 7fcfac3cba..3a25b9a6f1 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -14,9 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/slide_wrap.h" #include "history/history.h" #include "boxes/peer_list_controllers.h" +#include "base/binary_guard.h" +#include "lang/lang_keys.h" #include "apiwrap.h" #include "auth_session.h" -#include "lang/lang_keys.h" namespace { @@ -77,9 +78,19 @@ std::unique_ptr PrivacyExceptionsBoxControl } // namespace -EditPrivacyBox::EditPrivacyBox(QWidget*, std::unique_ptr controller) : BoxContent() -, _controller(std::move(controller)) +EditPrivacyBox::EditPrivacyBox( + QWidget*, + std::unique_ptr controller, + rpl::producer preloaded) +: _controller(std::move(controller)) , _loading(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout) { + std::move( + preloaded + ) | rpl::take( + 1 + ) | rpl::start_with_next([=](Value &&data) { + dataReady(std::move(data)); + }, lifetime()); } void EditPrivacyBox::prepare() { @@ -88,7 +99,11 @@ void EditPrivacyBox::prepare() { setTitle([this] { return _controller->title(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - loadData(); + if (_loading) { + _prepared = true; + } else { + createWidgets(); + } setDimensions(st::boxWideWidth, countDefaultHeight(st::boxWideWidth)); } @@ -215,13 +230,13 @@ QVector EditPrivacyBox::collectResult() { constexpr auto kMaxRules = 3; // allow users, disallow users, option auto result = QVector(); result.reserve(kMaxRules); - if (showExceptionLink(Exception::Always) && !_alwaysUsers.empty()) { - result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector(collectInputUsers(_alwaysUsers)))); + if (showExceptionLink(Exception::Always) && !_value.always.empty()) { + result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector(collectInputUsers(_value.always)))); } - if (showExceptionLink(Exception::Never) && !_neverUsers.empty()) { - result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector(collectInputUsers(_neverUsers)))); + if (showExceptionLink(Exception::Never) && !_value.never.empty()) { + result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector(collectInputUsers(_value.never)))); } - switch (_option) { + switch (_value.option) { case Option::Everyone: result.push_back(MTP_inputPrivacyValueAllowAll()); break; case Option::Contacts: result.push_back(MTP_inputPrivacyValueAllowContacts()); break; case Option::Nobody: result.push_back(MTP_inputPrivacyValueDisallowAll()); break; @@ -236,8 +251,8 @@ style::margins EditPrivacyBox::exceptionLinkMargins() const { std::vector> &EditPrivacyBox::exceptionUsers(Exception exception) { switch (exception) { - case Exception::Always: return _alwaysUsers; - case Exception::Never: return _neverUsers; + case Exception::Always: return _value.always; + case Exception::Never: return _value.never; } Unexpected("Invalid exception value."); } @@ -252,18 +267,18 @@ object_ptr> &EditPrivacyBox::exceptionLink(Excepti bool EditPrivacyBox::showExceptionLink(Exception exception) const { switch (exception) { - case Exception::Always: return (_option == Option::Contacts) || (_option == Option::Nobody); - case Exception::Never: return (_option == Option::Everyone) || (_option == Option::Contacts); + case Exception::Always: return (_value.option == Option::Contacts) || (_value.option == Option::Nobody); + case Exception::Never: return (_value.option == Option::Everyone) || (_value.option == Option::Contacts); } Unexpected("Invalid exception value."); } void EditPrivacyBox::createWidgets() { _loading.destroy(); - _optionGroup = std::make_shared>(_option); + _optionGroup = std::make_shared>(_value.option); auto createOption = [this](object_ptr> &widget, Option option, const QString &label) { - if (_controller->hasOption(option) || (_option == option)) { + if (_controller->hasOption(option) || (_value.option == option)) { widget.create(this, _optionGroup, option, label, st::defaultBoxCheckbox); } }; @@ -294,16 +309,18 @@ void EditPrivacyBox::createWidgets() { clearButtons(); addButton(langFactory(lng_settings_save), [this] { - auto someAreDisallowed = (_option != Option::Everyone) || !_neverUsers.empty(); + auto someAreDisallowed = (_value.option != Option::Everyone) || !_value.never.empty(); _controller->confirmSave(someAreDisallowed, crl::guard(this, [this] { - Auth().api().savePrivacy(_controller->key(), collectResult()); + Auth().api().savePrivacy( + _controller->apiKey(), + collectResult()); closeBox(); })); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); _optionGroup->setChangedCallback([this](Option value) { - _option = value; + _value.option = value; _alwaysLink->toggle( showExceptionLink(Exception::Always), anim::type::normal); @@ -323,54 +340,10 @@ void EditPrivacyBox::createWidgets() { setDimensions(st::boxWideWidth, resizeGetHeight(st::boxWideWidth)); } -void EditPrivacyBox::loadData() { - request(MTPaccount_GetPrivacy(_controller->key())).done([this](const MTPaccount_PrivacyRules &result) { - Expects(result.type() == mtpc_account_privacyRules); - auto &rules = result.c_account_privacyRules(); - App::feedUsers(rules.vusers); - - // This is simplified version of privacy rules interpretation. - // But it should be fine for all the apps that use the same subset of features. - auto optionSet = false; - auto setOption = [this, &optionSet](Option option) { - if (optionSet) return; - optionSet = true; - _option = option; - }; - auto feedRule = [this, &setOption](const MTPPrivacyRule &rule) { - switch (rule.type()) { - case mtpc_privacyValueAllowAll: setOption(Option::Everyone); break; - case mtpc_privacyValueAllowContacts: setOption(Option::Contacts); break; - case mtpc_privacyValueAllowUsers: { - auto &users = rule.c_privacyValueAllowUsers().vusers.v; - _alwaysUsers.reserve(_alwaysUsers.size() + users.size()); - for (auto &userId : users) { - auto user = App::user(UserId(userId.v)); - if (!base::contains(_neverUsers, user) && !base::contains(_alwaysUsers, user)) { - _alwaysUsers.push_back(user); - } - } - } break; - case mtpc_privacyValueDisallowContacts: // not supported, fall through - case mtpc_privacyValueDisallowAll: setOption(Option::Nobody); break; - case mtpc_privacyValueDisallowUsers: { - auto &users = rule.c_privacyValueDisallowUsers().vusers.v; - _neverUsers.reserve(_neverUsers.size() + users.size()); - for (auto &userId : users) { - auto user = App::user(UserId(userId.v)); - if (!base::contains(_alwaysUsers, user) && !base::contains(_neverUsers, user)) { - _neverUsers.push_back(user); - } - } - } break; - } - }; - for (auto &rule : rules.vrules.v) { - feedRule(rule); - } - feedRule(MTP_privacyValueDisallowAll()); // disallow by default. - +void EditPrivacyBox::dataReady(Value &&value) { + _value = std::move(value); + _loading.destroy(); + if (_prepared) { createWidgets(); - }).send(); + } } - diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index 264425561e..7c1b4fe606 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/abstract_box.h" #include "mtproto/sender.h" +#include "apiwrap.h" namespace Ui { class FlatLabel; @@ -23,11 +24,8 @@ class SlideWrap; class EditPrivacyBox : public BoxContent, private MTP::Sender { public: - enum class Option { - Everyone, - Contacts, - Nobody, - }; + using Value = ApiWrap::Privacy; + using Option = Value::Option; enum class Exception { Always, Never, @@ -35,7 +33,10 @@ public: class Controller { public: - virtual MTPInputPrivacyKey key() = 0; + using Key = ApiWrap::Privacy::Key; + + virtual Key key() = 0; + virtual MTPInputPrivacyKey apiKey() = 0; virtual QString title() = 0; virtual bool hasOption(Option option) { @@ -71,7 +72,10 @@ public: }; - EditPrivacyBox(QWidget*, std::unique_ptr controller); + EditPrivacyBox( + QWidget*, + std::unique_ptr controller, + rpl::producer preloaded); protected: void prepare() override; @@ -84,16 +88,18 @@ private: bool showExceptionLink(Exception exception) const; void createWidgets(); QVector collectResult(); - void loadData(); + void dataReady(Value &&value); int countDefaultHeight(int newWidth); void editExceptionUsers(Exception exception); QString exceptionLinkText(Exception exception); std::vector> &exceptionUsers(Exception exception); - object_ptr> &exceptionLink(Exception exception); + object_ptr> &exceptionLink( + Exception exception); std::unique_ptr _controller; - Option _option = Option::Everyone; + Value _value; + bool _prepared = false; std::shared_ptr> _optionGroup; object_ptr _loading; @@ -107,7 +113,4 @@ private: object_ptr> _neverLink = { nullptr }; object_ptr _exceptionsDescription = { nullptr }; - std::vector> _alwaysUsers; - std::vector> _neverUsers; - }; diff --git a/Telegram/SourceFiles/old_settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/old_settings/settings_privacy_controllers.cpp index 547a99b5cf..78f2501a0c 100644 --- a/Telegram/SourceFiles/old_settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/old_settings/settings_privacy_controllers.cpp @@ -220,7 +220,11 @@ std::unique_ptr BlockedBoxController::createRow(UserData *user) con return std::move(row); } -MTPInputPrivacyKey LastSeenPrivacyController::key() { +ApiWrap::Privacy::Key LastSeenPrivacyController::key() { + return Key::LastSeen; +} + +MTPInputPrivacyKey LastSeenPrivacyController::apiKey() { return MTP_inputPrivacyKeyStatusTimestamp(); } @@ -274,7 +278,11 @@ void LastSeenPrivacyController::confirmSave(bool someAreDisallowed, FnMut(std::make_unique())); } void PrivacyWidget::onCallsPrivacy() { - Ui::show(Box(std::make_unique())); } void PrivacyWidget::onGroupsInvitePrivacy() { - Ui::show(Box(std::make_unique())); } void PrivacyWidget::onAutoLock() { diff --git a/Telegram/SourceFiles/settings/settings_privacy_security.cpp b/Telegram/SourceFiles/settings/settings_privacy_security.cpp index 9a3d069013..f3011d4b36 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_security.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_security.cpp @@ -65,30 +65,60 @@ void SetupPrivacy(not_null container) { initBox)); }); - AddButton( - container, + using Privacy = ApiWrap::Privacy; + const auto PrivacyString = [](Privacy::Key key) { + Auth().api().reloadPrivacy(key); + return Auth().api().privacyValue( + key + ) | rpl::map([](const Privacy &value) { + const auto base = [&] { + using Option = Privacy::Option; + switch (value.option) { + case Option::Everyone: return lng_edit_privacy_everyone; + case Option::Contacts: return lng_edit_privacy_contacts; + case Option::Nobody: return lng_edit_privacy_nobody; + } + Unexpected("Value in Privacy::Option."); + }(); + auto add = QStringList(); + if (const auto never = value.never.size()) { + add.push_back("-" + QString::number(never)); + } + if (const auto always = value.always.size()) { + add.push_back("+" + QString::number(always)); + } + if (!add.isEmpty()) { + return lang(base) + " (" + add.join(", ") + ")"; + } else { + return lang(base); + } + }); + }; + using namespace OldSettings; + const auto add = [&](LangKey label, Privacy::Key key, auto controller) { + AddButtonWithLabel( + container, + label, + PrivacyString(key), + st::settingsButton + )->addClickHandler([=] { + Ui::show(Box( + controller(), + Auth().api().privacyValue(key))); + }); + }; + add( lng_settings_last_seen, - st::settingsButton - )->addClickHandler([] { - Ui::show(Box( - std::make_unique())); - }); - AddButton( - container, + Privacy::Key::LastSeen, + [] { return std::make_unique(); }); + add( lng_settings_calls, - st::settingsButton - )->addClickHandler([] { - Ui::show(Box( - std::make_unique())); - }); - AddButton( - container, + Privacy::Key::Calls, + [] { return std::make_unique(); }); + add( lng_settings_groups_invite, - st::settingsButton - )->addClickHandler([] { - Ui::show(Box( - std::make_unique())); - }); + Privacy::Key::Invites, + [] { return std::make_unique(); }); AddSkip(container, st::settingsPrivacySecurityPadding); AddDividerText(