mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Show current privacy values in settings section.
This commit is contained in:
parent
165511fb14
commit
12ebae01b0
@ -147,6 +147,16 @@ ApiWrap::MessageToSend::MessageToSend(not_null<History*> 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<AuthSession*> session)
|
||||
: _session(session)
|
||||
, _messageDataResolveDelayed([=] { resolveMessageDatas(); })
|
||||
@ -1880,112 +1890,139 @@ void ApiWrap::saveDraftToCloudDelayed(not_null<History*> history) {
|
||||
}
|
||||
|
||||
void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector<MTPInputPrivacyRule> &&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<MTPInputPrivacyRule>(std::move(rules)))).done([this, keyTypeId](const MTPaccount_PrivacyRules &result) {
|
||||
const auto requestId = request(MTPaccount_SetPrivacy(
|
||||
key,
|
||||
MTP_vector<MTPInputPrivacyRule>(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<MTPPrivacyRule> &rules) {
|
||||
if (keyTypeId == mtpc_privacyKeyStatusTimestamp) {
|
||||
enum class Rule {
|
||||
Unknown,
|
||||
Allow,
|
||||
Disallow,
|
||||
};
|
||||
auto userRules = QMap<UserId, Rule>();
|
||||
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<MTPPrivacyRule> &rules) {
|
||||
using Key = Privacy::Key;
|
||||
const auto key = [&]() -> base::optional<Key> {
|
||||
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<MTPContactStatus> &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<MTPPrivacyRule> &rules) {
|
||||
enum class Rule {
|
||||
Unknown,
|
||||
Allow,
|
||||
Disallow,
|
||||
};
|
||||
auto userRules = QMap<UserId, Rule>();
|
||||
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<MTPContactStatus> &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<void()> 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<MTPPrivacyRule> &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<MTPPrivacyRule> &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<Privacy> {
|
||||
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*> history) {
|
||||
if (history->unreadCount()) {
|
||||
readServerHistoryForce(history);
|
||||
|
@ -338,6 +338,26 @@ public:
|
||||
|
||||
void saveSelfBio(const QString &text, FnMut<void()> done);
|
||||
|
||||
struct Privacy {
|
||||
enum class Key {
|
||||
LastSeen,
|
||||
Calls,
|
||||
Invites,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
Contacts,
|
||||
Nobody,
|
||||
};
|
||||
Option option = Option::Everyone;
|
||||
std::vector<not_null<UserData*>> always;
|
||||
std::vector<not_null<UserData*>> never;
|
||||
|
||||
static MTPInputPrivacyKey Input(Key key);
|
||||
};
|
||||
void reloadPrivacy(Privacy::Key key);
|
||||
rpl::producer<Privacy> privacyValue(Privacy::Key key);
|
||||
|
||||
~ApiWrap();
|
||||
|
||||
private:
|
||||
@ -521,6 +541,12 @@ private:
|
||||
|
||||
void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file);
|
||||
|
||||
Privacy parsePrivacy(const QVector<MTPPrivacyRule> &rules);
|
||||
void pushPrivacy(
|
||||
Privacy::Key key,
|
||||
const QVector<MTPPrivacyRule> &rules);
|
||||
void updatePrivacyLastSeens(const QVector<MTPPrivacyRule> &rules);
|
||||
|
||||
not_null<AuthSession*> _session;
|
||||
|
||||
MessageDataRequests _messageDataRequests;
|
||||
@ -678,4 +704,8 @@ private:
|
||||
FnMut<void()> _saveBioDone;
|
||||
QString _saveBioText;
|
||||
|
||||
base::flat_map<Privacy::Key, mtpRequestId> _privacyRequestIds;
|
||||
base::flat_map<Privacy::Key, Privacy> _privacyValues;
|
||||
std::map<Privacy::Key, rpl::event_stream<Privacy>> _privacyChanges;
|
||||
|
||||
};
|
||||
|
@ -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<PrivacyExceptionsBoxController::Row> PrivacyExceptionsBoxControl
|
||||
|
||||
} // namespace
|
||||
|
||||
EditPrivacyBox::EditPrivacyBox(QWidget*, std::unique_ptr<Controller> controller) : BoxContent()
|
||||
, _controller(std::move(controller))
|
||||
EditPrivacyBox::EditPrivacyBox(
|
||||
QWidget*,
|
||||
std::unique_ptr<Controller> controller,
|
||||
rpl::producer<Value> 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<MTPInputPrivacyRule> EditPrivacyBox::collectResult() {
|
||||
constexpr auto kMaxRules = 3; // allow users, disallow users, option
|
||||
auto result = QVector<MTPInputPrivacyRule>();
|
||||
result.reserve(kMaxRules);
|
||||
if (showExceptionLink(Exception::Always) && !_alwaysUsers.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector<MTPInputUser>(collectInputUsers(_alwaysUsers))));
|
||||
if (showExceptionLink(Exception::Always) && !_value.always.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector<MTPInputUser>(collectInputUsers(_value.always))));
|
||||
}
|
||||
if (showExceptionLink(Exception::Never) && !_neverUsers.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector<MTPInputUser>(collectInputUsers(_neverUsers))));
|
||||
if (showExceptionLink(Exception::Never) && !_value.never.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector<MTPInputUser>(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<not_null<UserData*>> &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<Ui::SlideWrap<Ui::LinkButton>> &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<Ui::RadioenumGroup<Option>>(_option);
|
||||
_optionGroup = std::make_shared<Ui::RadioenumGroup<Option>>(_value.option);
|
||||
|
||||
auto createOption = [this](object_ptr<Ui::Radioenum<Option>> &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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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> controller);
|
||||
EditPrivacyBox(
|
||||
QWidget*,
|
||||
std::unique_ptr<Controller> controller,
|
||||
rpl::producer<Value> preloaded);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@ -84,16 +88,18 @@ private:
|
||||
bool showExceptionLink(Exception exception) const;
|
||||
void createWidgets();
|
||||
QVector<MTPInputPrivacyRule> collectResult();
|
||||
void loadData();
|
||||
void dataReady(Value &&value);
|
||||
int countDefaultHeight(int newWidth);
|
||||
|
||||
void editExceptionUsers(Exception exception);
|
||||
QString exceptionLinkText(Exception exception);
|
||||
std::vector<not_null<UserData*>> &exceptionUsers(Exception exception);
|
||||
object_ptr<Ui::SlideWrap<Ui::LinkButton>> &exceptionLink(Exception exception);
|
||||
object_ptr<Ui::SlideWrap<Ui::LinkButton>> &exceptionLink(
|
||||
Exception exception);
|
||||
|
||||
std::unique_ptr<Controller> _controller;
|
||||
Option _option = Option::Everyone;
|
||||
Value _value;
|
||||
bool _prepared = false;
|
||||
|
||||
std::shared_ptr<Ui::RadioenumGroup<Option>> _optionGroup;
|
||||
object_ptr<Ui::FlatLabel> _loading;
|
||||
@ -107,7 +113,4 @@ private:
|
||||
object_ptr<Ui::SlideWrap<Ui::LinkButton>> _neverLink = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _exceptionsDescription = { nullptr };
|
||||
|
||||
std::vector<not_null<UserData*>> _alwaysUsers;
|
||||
std::vector<not_null<UserData*>> _neverUsers;
|
||||
|
||||
};
|
||||
|
@ -220,7 +220,11 @@ std::unique_ptr<PeerListRow> 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<void()
|
||||
}
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey GroupsInvitePrivacyController::key() {
|
||||
ApiWrap::Privacy::Key GroupsInvitePrivacyController::key() {
|
||||
return Key::Invites;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey GroupsInvitePrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyChatInvite();
|
||||
}
|
||||
|
||||
@ -310,7 +318,11 @@ QString GroupsInvitePrivacyController::exceptionsDescription() {
|
||||
return lang(lng_edit_privacy_groups_exceptions);
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey CallsPrivacyController::key() {
|
||||
ApiWrap::Privacy::Key CallsPrivacyController::key() {
|
||||
return Key::Calls;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey CallsPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyPhoneCall();
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,8 @@ public:
|
||||
using Option = EditPrivacyBox::Option;
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
MTPInputPrivacyKey key() override;
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
QString title() override;
|
||||
QString description() override;
|
||||
@ -59,7 +60,8 @@ public:
|
||||
using Option = EditPrivacyBox::Option;
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
MTPInputPrivacyKey key() override;
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
QString title() override;
|
||||
bool hasOption(Option option) override;
|
||||
@ -75,7 +77,8 @@ public:
|
||||
using Option = EditPrivacyBox::Option;
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
MTPInputPrivacyKey key() override;
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
QString title() override;
|
||||
QString description() override;
|
||||
|
@ -286,15 +286,12 @@ void PrivacyWidget::onBlockedUsers() {
|
||||
}
|
||||
|
||||
void PrivacyWidget::onLastSeenPrivacy() {
|
||||
Ui::show(Box<EditPrivacyBox>(std::make_unique<LastSeenPrivacyController>()));
|
||||
}
|
||||
|
||||
void PrivacyWidget::onCallsPrivacy() {
|
||||
Ui::show(Box<EditPrivacyBox>(std::make_unique<CallsPrivacyController>()));
|
||||
}
|
||||
|
||||
void PrivacyWidget::onGroupsInvitePrivacy() {
|
||||
Ui::show(Box<EditPrivacyBox>(std::make_unique<GroupsInvitePrivacyController>()));
|
||||
}
|
||||
|
||||
void PrivacyWidget::onAutoLock() {
|
||||
|
@ -65,30 +65,60 @@ void SetupPrivacy(not_null<Ui::VerticalLayout*> 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<EditPrivacyBox>(
|
||||
controller(),
|
||||
Auth().api().privacyValue(key)));
|
||||
});
|
||||
};
|
||||
add(
|
||||
lng_settings_last_seen,
|
||||
st::settingsButton
|
||||
)->addClickHandler([] {
|
||||
Ui::show(Box<EditPrivacyBox>(
|
||||
std::make_unique<OldSettings::LastSeenPrivacyController>()));
|
||||
});
|
||||
AddButton(
|
||||
container,
|
||||
Privacy::Key::LastSeen,
|
||||
[] { return std::make_unique<LastSeenPrivacyController>(); });
|
||||
add(
|
||||
lng_settings_calls,
|
||||
st::settingsButton
|
||||
)->addClickHandler([] {
|
||||
Ui::show(Box<EditPrivacyBox>(
|
||||
std::make_unique<OldSettings::CallsPrivacyController>()));
|
||||
});
|
||||
AddButton(
|
||||
container,
|
||||
Privacy::Key::Calls,
|
||||
[] { return std::make_unique<CallsPrivacyController>(); });
|
||||
add(
|
||||
lng_settings_groups_invite,
|
||||
st::settingsButton
|
||||
)->addClickHandler([] {
|
||||
Ui::show(Box<EditPrivacyBox>(
|
||||
std::make_unique<OldSettings::GroupsInvitePrivacyController>()));
|
||||
});
|
||||
Privacy::Key::Invites,
|
||||
[] { return std::make_unique<GroupsInvitePrivacyController>(); });
|
||||
|
||||
AddSkip(container, st::settingsPrivacySecurityPadding);
|
||||
AddDividerText(
|
||||
|
Loading…
Reference in New Issue
Block a user