Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
437d35d8c4 | ||
|
|
36a5dd8d8b | ||
|
|
d8e99b4860 | ||
|
|
3cddcaa039 | ||
|
|
49078e5679 | ||
|
|
1dec054766 | ||
|
|
91ef6f13c8 | ||
|
|
73c8f16340 | ||
|
|
cbad2469db | ||
|
|
0ae260c6e1 | ||
|
|
221ded6d54 | ||
|
|
6f80811ecd | ||
|
|
5bd73bab9b | ||
|
|
ac86f3e5bd | ||
|
|
bae6a29326 | ||
|
|
dcf86f55af |
@@ -91,12 +91,16 @@ PRIVATE
|
||||
api/api_attached_stickers.h
|
||||
api/api_authorizations.cpp
|
||||
api/api_authorizations.h
|
||||
api/api_blocked_peers.cpp
|
||||
api/api_blocked_peers.h
|
||||
api/api_bot.cpp
|
||||
api/api_bot.h
|
||||
api/api_chat_filters.cpp
|
||||
api/api_chat_filters.h
|
||||
api/api_chat_invite.cpp
|
||||
api/api_chat_invite.h
|
||||
api/api_cloud_password.cpp
|
||||
api/api_cloud_password.h
|
||||
api/api_common.h
|
||||
api/api_editing.cpp
|
||||
api/api_editing.h
|
||||
@@ -124,6 +128,8 @@ PRIVATE
|
||||
api/api_toggling_media.h
|
||||
api/api_updates.cpp
|
||||
api/api_updates.h
|
||||
api/api_user_privacy.cpp
|
||||
api/api_user_privacy.h
|
||||
boxes/filters/edit_filter_box.cpp
|
||||
boxes/filters/edit_filter_box.h
|
||||
boxes/filters/edit_filter_chats_list.cpp
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.9.0.0" />
|
||||
Version="2.9.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,9,0,0
|
||||
PRODUCTVERSION 2,9,0,0
|
||||
FILEVERSION 2,9,2,0
|
||||
PRODUCTVERSION 2,9,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.9.0.0"
|
||||
VALUE "FileVersion", "2.9.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.9.0.0"
|
||||
VALUE "ProductVersion", "2.9.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,9,0,0
|
||||
PRODUCTVERSION 2,9,0,0
|
||||
FILEVERSION 2,9,2,0
|
||||
PRODUCTVERSION 2,9,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "2.9.0.0"
|
||||
VALUE "FileVersion", "2.9.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.9.0.0"
|
||||
VALUE "ProductVersion", "2.9.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
173
Telegram/SourceFiles/api/api_blocked_peers.cpp
Normal file
173
Telegram/SourceFiles/api/api_blocked_peers.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
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_blocked_peers.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_id.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kBlockedFirstSlice = 16;
|
||||
constexpr auto kBlockedPerPage = 40;
|
||||
|
||||
BlockedPeers::Slice TLToSlice(
|
||||
const MTPcontacts_Blocked &blocked,
|
||||
Data::Session &owner) {
|
||||
const auto create = [&](int count, const QVector<MTPPeerBlocked> &list) {
|
||||
auto slice = BlockedPeers::Slice();
|
||||
slice.total = std::max(count, list.size());
|
||||
slice.list.reserve(list.size());
|
||||
for (const auto &contact : list) {
|
||||
contact.match([&](const MTPDpeerBlocked &data) {
|
||||
slice.list.push_back({
|
||||
.id = peerFromMTP(data.vpeer_id()),
|
||||
.date = data.vdate().v,
|
||||
});
|
||||
});
|
||||
}
|
||||
return slice;
|
||||
};
|
||||
return blocked.match([&](const MTPDcontacts_blockedSlice &data) {
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
return create(data.vcount().v, data.vblocked().v);
|
||||
}, [&](const MTPDcontacts_blocked &data) {
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
return create(0, data.vblocked().v);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BlockedPeers::BlockedPeers(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::Item::operator==(const Item &other) const {
|
||||
return (id == other.id) && (date == other.date);
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::Item::operator!=(const Item &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::operator==(const BlockedPeers::Slice &other) const {
|
||||
return (total == other.total) && (list == other.list);
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::operator!=(const BlockedPeers::Slice &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void BlockedPeers::block(not_null<PeerData*> peer) {
|
||||
if (peer->isBlocked()) {
|
||||
_session->changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
|
||||
const auto requestId = _api.request(MTPcontacts_Block(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_slice) {
|
||||
_slice->list.insert(
|
||||
_slice->list.begin(),
|
||||
{ peer->id, base::unixtime::now() });
|
||||
++_slice->total;
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void BlockedPeers::unblock(not_null<PeerData*> peer, Fn<void()> onDone) {
|
||||
if (!peer->isBlocked()) {
|
||||
_session->changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
return;
|
||||
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPcontacts_Unblock(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(false);
|
||||
if (_slice) {
|
||||
auto &list = _slice->list;
|
||||
for (auto i = list.begin(); i != list.end(); ++i) {
|
||||
if (i->id == peer->id) {
|
||||
list.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_slice->total > list.size()) {
|
||||
--_slice->total;
|
||||
}
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
|
||||
void BlockedPeers::reload() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
request(0, [=](Slice &&slice) {
|
||||
if (!_slice || *_slice != slice) {
|
||||
_slice = slice;
|
||||
_changes.fire(std::move(slice));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto BlockedPeers::slice() -> rpl::producer<BlockedPeers::Slice> {
|
||||
if (!_slice) {
|
||||
reload();
|
||||
}
|
||||
return _slice
|
||||
? _changes.events_starting_with_copy(*_slice)
|
||||
: (_changes.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPcontacts_GetBlocked(
|
||||
MTP_int(offset),
|
||||
MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_requestId = 0;
|
||||
onDone(TLToSlice(result, _session->data()));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
60
Telegram/SourceFiles/api/api_blocked_peers.h
Normal file
60
Telegram/SourceFiles/api/api_blocked_peers.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
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 BlockedPeers final {
|
||||
public:
|
||||
struct Slice {
|
||||
struct Item {
|
||||
PeerId id;
|
||||
TimeId date = 0;
|
||||
|
||||
bool operator==(const Item &other) const;
|
||||
bool operator!=(const Item &other) const;
|
||||
};
|
||||
|
||||
QVector<Item> list;
|
||||
int total = 0;
|
||||
|
||||
bool operator==(const Slice &other) const;
|
||||
bool operator!=(const Slice &other) const;
|
||||
};
|
||||
|
||||
explicit BlockedPeers(not_null<ApiWrap*> api);
|
||||
|
||||
void reload();
|
||||
rpl::producer<Slice> slice();
|
||||
void request(int offset, Fn<void(Slice)> onDone);
|
||||
|
||||
void block(not_null<PeerData*> peer);
|
||||
void unblock(not_null<PeerData*> peer, Fn<void()> onDone = nullptr);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
|
||||
mtpRequestId _requestId = 0;
|
||||
std::optional<Slice> _slice;
|
||||
rpl::event_stream<Slice> _changes;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_bot.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
@@ -168,7 +169,7 @@ void SendBotCallbackDataWithPassword(
|
||||
if (!button || button->requestId) {
|
||||
return;
|
||||
}
|
||||
api->reloadPasswordState();
|
||||
api->cloudPassword().reload();
|
||||
SendBotCallbackData(item, row, column, MTP_inputCheckPasswordEmpty(), [=](const MTP::Error &error) {
|
||||
auto box = PrePasswordErrorBox(
|
||||
error,
|
||||
@@ -181,7 +182,7 @@ void SendBotCallbackDataWithPassword(
|
||||
} else {
|
||||
auto lifetime = std::make_shared<rpl::lifetime>();
|
||||
button->requestId = -1;
|
||||
api->passwordState(
|
||||
api->cloudPassword().state(
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) mutable {
|
||||
|
||||
86
Telegram/SourceFiles/api/api_cloud_password.cpp
Normal file
86
Telegram/SourceFiles/api/api_cloud_password.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
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_cloud_password.h"
|
||||
|
||||
#include "base/openssl_help.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
// #TODO Add ability to set recovery email separately.
|
||||
|
||||
CloudPassword::CloudPassword(not_null<ApiWrap*> api)
|
||||
: _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void CloudPassword::reload() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPaccount_GetPassword(
|
||||
)).done([=](const MTPaccount_Password &result) {
|
||||
_requestId = 0;
|
||||
result.match([&](const MTPDaccount_password &data) {
|
||||
openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v));
|
||||
if (_state) {
|
||||
*_state = Core::ParseCloudPasswordState(data);
|
||||
} else {
|
||||
_state = std::make_unique<Core::CloudPasswordState>(
|
||||
Core::ParseCloudPasswordState(data));
|
||||
}
|
||||
_stateChanges.fire_copy(*_state);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void CloudPassword::applyPendingReset(
|
||||
const MTPaccount_ResetPasswordResult &data) {
|
||||
if (!_state) {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
data.match([&](const MTPDaccount_resetPasswordOk &data) {
|
||||
reload();
|
||||
}, [&](const MTPDaccount_resetPasswordRequestedWait &data) {
|
||||
const auto until = data.vuntil_date().v;
|
||||
if (_state->pendingResetDate != until) {
|
||||
_state->pendingResetDate = until;
|
||||
_stateChanges.fire_copy(*_state);
|
||||
}
|
||||
}, [&](const MTPDaccount_resetPasswordFailedWait &data) {
|
||||
});
|
||||
}
|
||||
|
||||
void CloudPassword::clearUnconfirmedPassword() {
|
||||
_requestId = _api.request(MTPaccount_CancelPasswordEmail(
|
||||
)).done([=](const MTPBool &result) {
|
||||
_requestId = 0;
|
||||
reload();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
reload();
|
||||
}).send();
|
||||
}
|
||||
|
||||
rpl::producer<Core::CloudPasswordState> CloudPassword::state() const {
|
||||
return _state
|
||||
? _stateChanges.events_starting_with_copy(*_state)
|
||||
: (_stateChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
auto CloudPassword::stateCurrent() const
|
||||
-> std::optional<Core::CloudPasswordState> {
|
||||
return _state
|
||||
? base::make_optional(*_state)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
42
Telegram/SourceFiles/api/api_cloud_password.h
Normal file
42
Telegram/SourceFiles/api/api_cloud_password.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
namespace Core {
|
||||
struct CloudPasswordState;
|
||||
} // namespace Core
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class CloudPassword final {
|
||||
public:
|
||||
explicit CloudPassword(not_null<ApiWrap*> api);
|
||||
|
||||
void reload();
|
||||
void applyPendingReset(const MTPaccount_ResetPasswordResult &data);
|
||||
void clearUnconfirmedPassword();
|
||||
rpl::producer<Core::CloudPasswordState> state() const;
|
||||
std::optional<Core::CloudPasswordState> stateCurrent() const;
|
||||
|
||||
private:
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _requestId = 0;
|
||||
std::unique_ptr<Core::CloudPasswordState> _state;
|
||||
rpl::event_stream<Core::CloudPasswordState> _stateChanges;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "mtproto/mtp_instance.h"
|
||||
@@ -1954,13 +1955,10 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (const auto key = ApiWrap::Privacy::KeyFromMTP(d.vkey().type())) {
|
||||
if (allLoaded()) {
|
||||
session().api().handlePrivacyChange(*key, d.vrules());
|
||||
} else {
|
||||
session().api().reloadPrivacy(*key);
|
||||
}
|
||||
}
|
||||
session().api().userPrivacy().apply(
|
||||
d.vkey().type(),
|
||||
d.vrules(),
|
||||
allLoaded());
|
||||
} break;
|
||||
|
||||
case mtpc_updatePinnedDialogs: {
|
||||
|
||||
303
Telegram/SourceFiles/api/api_user_privacy.cpp
Normal file
303
Telegram/SourceFiles/api/api_user_privacy.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
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_user_privacy.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_id.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxRules = 3; // Allow users, disallow users, Option.
|
||||
|
||||
using TLInputRules = MTPVector<MTPInputPrivacyRule>;
|
||||
using TLRules = MTPVector<MTPPrivacyRule>;
|
||||
|
||||
TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
|
||||
const auto collectInputUsers = [](const auto &peers) {
|
||||
auto result = QVector<MTPInputUser>();
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.push_back(user->inputUser);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto collectInputChats = [](const auto &peers) {
|
||||
auto result = QVector<MTPint>(); // #TODO ids
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (!peer->isUser()) {
|
||||
result.push_back(peerToBareMTPInt(peer->id));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto result = QVector<MTPInputPrivacyRule>();
|
||||
result.reserve(kMaxRules);
|
||||
if (!rule.ignoreAlways) {
|
||||
const auto users = collectInputUsers(rule.always);
|
||||
const auto chats = collectInputChats(rule.always);
|
||||
if (!users.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueAllowUsers(
|
||||
MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueAllowChatParticipants(
|
||||
MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
if (!rule.ignoreNever) {
|
||||
const auto users = collectInputUsers(rule.never);
|
||||
const auto chats = collectInputChats(rule.never);
|
||||
if (!users.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueDisallowUsers(
|
||||
MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueDisallowChatParticipants(
|
||||
MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
result.push_back([&] {
|
||||
using Option = UserPrivacy::Option;
|
||||
switch (rule.option) {
|
||||
case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
|
||||
case Option::Contacts: return MTP_inputPrivacyValueAllowContacts();
|
||||
case Option::Nobody: return MTP_inputPrivacyValueDisallowAll();
|
||||
}
|
||||
Unexpected("Option value in Api::UserPrivacy::RulesToTL.");
|
||||
}());
|
||||
|
||||
|
||||
return MTP_vector<MTPInputPrivacyRule>(std::move(result));
|
||||
}
|
||||
|
||||
UserPrivacy::Rule TLToRules(const TLRules &rules, Data::Session &owner) {
|
||||
// This is simplified version of privacy rules interpretation.
|
||||
// But it should be fine for all the apps
|
||||
// that use the same subset of features.
|
||||
using Option = UserPrivacy::Option;
|
||||
auto result = UserPrivacy::Rule();
|
||||
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 = owner.user(UserId(userId.v));
|
||||
if (!base::contains(never, user)
|
||||
&& !base::contains(always, user)) {
|
||||
always.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueAllowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
always.reserve(always.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = owner.chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: owner.channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(never, peer)
|
||||
&& !base::contains(always, peer)) {
|
||||
always.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
}, [&](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 = owner.user(UserId(userId.v));
|
||||
if (!base::contains(always, user)
|
||||
&& !base::contains(never, user)) {
|
||||
never.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueDisallowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
never.reserve(never.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = owner.chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: owner.channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(always, peer)
|
||||
&& !base::contains(never, peer)) {
|
||||
never.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
for (const auto &rule : rules.v) {
|
||||
feed(rule);
|
||||
}
|
||||
feed(MTP_privacyValueDisallowAll()); // Disallow by default.
|
||||
return result;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) {
|
||||
using Key = UserPrivacy::Key;
|
||||
switch (key) {
|
||||
case Key::Calls: return MTP_inputPrivacyKeyPhoneCall();
|
||||
case Key::Invites: return MTP_inputPrivacyKeyChatInvite();
|
||||
case Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber();
|
||||
case Key::AddedByPhone:
|
||||
return MTP_inputPrivacyKeyAddedByPhone();
|
||||
case Key::LastSeen:
|
||||
return MTP_inputPrivacyKeyStatusTimestamp();
|
||||
case Key::CallsPeer2Peer:
|
||||
return MTP_inputPrivacyKeyPhoneP2P();
|
||||
case Key::Forwards:
|
||||
return MTP_inputPrivacyKeyForwards();
|
||||
case Key::ProfilePhoto:
|
||||
return MTP_inputPrivacyKeyProfilePhoto();
|
||||
}
|
||||
Unexpected("Key in Api::UserPrivacy::KetToTL.");
|
||||
}
|
||||
|
||||
std::optional<UserPrivacy::Key> TLToKey(mtpTypeId type) {
|
||||
using Key = UserPrivacy::Key;
|
||||
switch (type) {
|
||||
case mtpc_privacyKeyPhoneNumber:
|
||||
case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber;
|
||||
case mtpc_privacyKeyAddedByPhone:
|
||||
case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone;
|
||||
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;
|
||||
case mtpc_privacyKeyPhoneP2P:
|
||||
case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer;
|
||||
case mtpc_privacyKeyForwards:
|
||||
case mtpc_inputPrivacyKeyForwards: return Key::Forwards;
|
||||
case mtpc_privacyKeyProfilePhoto:
|
||||
case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UserPrivacy::UserPrivacy(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void UserPrivacy::save(
|
||||
Key key,
|
||||
const UserPrivacy::Rule &rule) {
|
||||
const auto tlKey = KeyToTL(key);
|
||||
const auto keyTypeId = tlKey.type();
|
||||
const auto it = _privacySaveRequests.find(keyTypeId);
|
||||
if (it != _privacySaveRequests.cend()) {
|
||||
_api.request(it->second).cancel();
|
||||
_privacySaveRequests.erase(it);
|
||||
}
|
||||
|
||||
const auto requestId = _api.request(MTPaccount_SetPrivacy(
|
||||
tlKey,
|
||||
RulesToTL(rule)
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
apply(keyTypeId, data.vrules(), true);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
}).send();
|
||||
|
||||
_privacySaveRequests.emplace(keyTypeId, requestId);
|
||||
}
|
||||
|
||||
void UserPrivacy::apply(
|
||||
mtpTypeId type,
|
||||
const TLRules &rules,
|
||||
bool allLoaded) {
|
||||
if (const auto key = TLToKey(type)) {
|
||||
if (!allLoaded) {
|
||||
reload(*key);
|
||||
return;
|
||||
}
|
||||
pushPrivacy(*key, rules);
|
||||
if ((*key) == Key::LastSeen) {
|
||||
_session->api().updatePrivacyLastSeens();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserPrivacy::reload(Key key) {
|
||||
if (_privacyRequestIds.contains(key)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPaccount_GetPrivacy(
|
||||
KeyToTL(key)
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
_privacyRequestIds.erase(key);
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
pushPrivacy(key, data.vrules());
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacyRequestIds.erase(key);
|
||||
}).send();
|
||||
_privacyRequestIds.emplace(key, requestId);
|
||||
}
|
||||
|
||||
void UserPrivacy::pushPrivacy(Key key, const TLRules &rules) {
|
||||
const auto &saved = (_privacyValues[key] =
|
||||
TLToRules(rules, _session->data()));
|
||||
const auto i = _privacyChanges.find(key);
|
||||
if (i != end(_privacyChanges)) {
|
||||
i->second.fire_copy(saved);
|
||||
}
|
||||
}
|
||||
|
||||
auto UserPrivacy::value(Key key) -> rpl::producer<UserPrivacy::Rule> {
|
||||
if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) {
|
||||
return _privacyChanges[key].events_starting_with_copy(i->second);
|
||||
} else {
|
||||
return _privacyChanges[key].events();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
73
Telegram/SourceFiles/api/api_user_privacy.h
Normal file
73
Telegram/SourceFiles/api/api_user_privacy.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
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 UserPrivacy final {
|
||||
public:
|
||||
enum class Key {
|
||||
PhoneNumber,
|
||||
AddedByPhone,
|
||||
LastSeen,
|
||||
Calls,
|
||||
Invites,
|
||||
CallsPeer2Peer,
|
||||
Forwards,
|
||||
ProfilePhoto,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
Contacts,
|
||||
Nobody,
|
||||
};
|
||||
struct Rule {
|
||||
Option option = Option::Everyone;
|
||||
std::vector<not_null<PeerData*>> always;
|
||||
std::vector<not_null<PeerData*>> never;
|
||||
bool ignoreAlways = false;
|
||||
bool ignoreNever = false;
|
||||
};
|
||||
|
||||
explicit UserPrivacy(not_null<ApiWrap*> api);
|
||||
|
||||
void save(
|
||||
Key key,
|
||||
const UserPrivacy::Rule &rule);
|
||||
void apply(
|
||||
mtpTypeId type,
|
||||
const MTPVector<MTPPrivacyRule> &rules,
|
||||
bool allLoaded);
|
||||
|
||||
void reload(Key key);
|
||||
rpl::producer<Rule> value(Key key);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
void pushPrivacy(Key key, const MTPVector<MTPPrivacyRule> &rules);
|
||||
|
||||
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
|
||||
|
||||
base::flat_map<Key, mtpRequestId> _privacyRequestIds;
|
||||
base::flat_map<Key, Rule> _privacyValues;
|
||||
std::map<Key, rpl::event_stream<Rule>> _privacyChanges;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_attached_stickers.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "api/api_hash.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "api/api_media.h"
|
||||
@@ -18,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_sensitive_content.h"
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "data/data_changes.h"
|
||||
@@ -42,7 +45,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "core/application.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "base/call_delayed.h"
|
||||
@@ -108,7 +110,6 @@ constexpr auto kStickersByEmojiInvalidateTimeout = crl::time(60 * 60 * 1000);
|
||||
constexpr auto kNotifySettingSaveTimeout = crl::time(1000);
|
||||
constexpr auto kDialogsFirstLoad = 20;
|
||||
constexpr auto kDialogsPerPage = 500;
|
||||
constexpr auto kBlockedFirstSlice = 16;
|
||||
|
||||
using PhotoFileLocationId = Data::PhotoFileLocationId;
|
||||
using DocumentFileLocationId = Data::DocumentFileLocationId;
|
||||
@@ -120,65 +121,6 @@ using UpdatedFileReferences = Data::UpdatedFileReferences;
|
||||
|
||||
} // namespace
|
||||
|
||||
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::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber();
|
||||
case Privacy::Key::AddedByPhone:
|
||||
return MTP_inputPrivacyKeyAddedByPhone();
|
||||
case Privacy::Key::LastSeen:
|
||||
return MTP_inputPrivacyKeyStatusTimestamp();
|
||||
case Privacy::Key::CallsPeer2Peer:
|
||||
return MTP_inputPrivacyKeyPhoneP2P();
|
||||
case Privacy::Key::Forwards:
|
||||
return MTP_inputPrivacyKeyForwards();
|
||||
case Privacy::Key::ProfilePhoto:
|
||||
return MTP_inputPrivacyKeyProfilePhoto();
|
||||
}
|
||||
Unexpected("Key in ApiWrap::Privacy::Input.");
|
||||
}
|
||||
|
||||
std::optional<ApiWrap::Privacy::Key> ApiWrap::Privacy::KeyFromMTP(
|
||||
mtpTypeId type) {
|
||||
using Key = Privacy::Key;
|
||||
switch (type) {
|
||||
case mtpc_privacyKeyPhoneNumber:
|
||||
case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber;
|
||||
case mtpc_privacyKeyAddedByPhone:
|
||||
case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone;
|
||||
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;
|
||||
case mtpc_privacyKeyPhoneP2P:
|
||||
case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer;
|
||||
case mtpc_privacyKeyForwards:
|
||||
case mtpc_inputPrivacyKeyForwards: return Key::Forwards;
|
||||
case mtpc_privacyKeyProfilePhoto:
|
||||
case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::Item::operator==(const Item &other) const {
|
||||
return (peer == other.peer) && (date == other.date);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::Item::operator!=(const Item &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::operator==(const BlockedPeersSlice &other) const {
|
||||
return (total == other.total) && (list == other.list);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::operator!=(const BlockedPeersSlice &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
: MTP::Sender(&session->account().mtp())
|
||||
, _session(session)
|
||||
@@ -192,9 +134,12 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
|
||||
, _authorizations(std::make_unique<Api::Authorizations>(this))
|
||||
, _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
|
||||
, _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
|
||||
, _cloudPassword(std::make_unique<Api::CloudPassword>(this))
|
||||
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
|
||||
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
|
||||
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this))
|
||||
, _userPrivacy(std::make_unique<Api::UserPrivacy>(this))
|
||||
, _inviteLinks(std::make_unique<Api::InviteLinks>(this)) {
|
||||
crl::on_main(session, [=] {
|
||||
// You can't use _session->lifetime() in the constructor,
|
||||
@@ -2175,68 +2120,6 @@ void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::blockPeer(not_null<PeerData*> peer) {
|
||||
if (peer->isBlocked()) {
|
||||
session().changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
|
||||
const auto requestId = request(MTPcontacts_Block(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_blockedPeersSlice) {
|
||||
_blockedPeersSlice->list.insert(
|
||||
_blockedPeersSlice->list.begin(),
|
||||
{ peer, base::unixtime::now() });
|
||||
++_blockedPeersSlice->total;
|
||||
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone) {
|
||||
if (!peer->isBlocked()) {
|
||||
session().changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
return;
|
||||
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPcontacts_Unblock(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(false);
|
||||
if (_blockedPeersSlice) {
|
||||
auto &list = _blockedPeersSlice->list;
|
||||
for (auto i = list.begin(); i != list.end(); ++i) {
|
||||
if (i->peer == peer) {
|
||||
list.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_blockedPeersSlice->total > list.size()) {
|
||||
--_blockedPeersSlice->total;
|
||||
}
|
||||
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
|
||||
}
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
||||
const auto key = [&] {
|
||||
switch (peer.type()) {
|
||||
@@ -2309,45 +2192,7 @@ void ApiWrap::saveDraftToCloudDelayed(not_null<History*> history) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::savePrivacy(
|
||||
const MTPInputPrivacyKey &key,
|
||||
QVector<MTPInputPrivacyRule> &&rules) {
|
||||
const auto keyTypeId = key.type();
|
||||
const auto it = _privacySaveRequests.find(keyTypeId);
|
||||
if (it != _privacySaveRequests.cend()) {
|
||||
request(it->second).cancel();
|
||||
_privacySaveRequests.erase(it);
|
||||
}
|
||||
|
||||
const auto requestId = request(MTPaccount_SetPrivacy(
|
||||
key,
|
||||
MTP_vector<MTPInputPrivacyRule>(std::move(rules))
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
if (const auto key = Privacy::KeyFromMTP(keyTypeId)) {
|
||||
handlePrivacyChange(*key, data.vrules());
|
||||
}
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
}).send();
|
||||
|
||||
_privacySaveRequests.emplace(keyTypeId, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::handlePrivacyChange(
|
||||
Privacy::Key key,
|
||||
const MTPVector<MTPPrivacyRule> &rules) {
|
||||
pushPrivacy(key, rules.v);
|
||||
if (key == Privacy::Key::LastSeen) {
|
||||
updatePrivacyLastSeens(rules.v);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::updatePrivacyLastSeens(const QVector<MTPPrivacyRule> &rules) {
|
||||
void ApiWrap::updatePrivacyLastSeens() {
|
||||
const auto now = base::unixtime::now();
|
||||
_session->data().enumerateUsers([&](UserData *user) {
|
||||
if (user->isSelf() || !user->isFullLoaded()) {
|
||||
@@ -4742,69 +4587,6 @@ void ApiWrap::clearPeerPhoto(not_null<PhotoData*> photo) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::reloadPasswordState() {
|
||||
if (_passwordRequestId) {
|
||||
return;
|
||||
}
|
||||
_passwordRequestId = request(MTPaccount_GetPassword(
|
||||
)).done([=](const MTPaccount_Password &result) {
|
||||
_passwordRequestId = 0;
|
||||
result.match([&](const MTPDaccount_password &data) {
|
||||
openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v));
|
||||
if (_passwordState) {
|
||||
*_passwordState = Core::ParseCloudPasswordState(data);
|
||||
} else {
|
||||
_passwordState = std::make_unique<Core::CloudPasswordState>(
|
||||
Core::ParseCloudPasswordState(data));
|
||||
}
|
||||
_passwordStateChanges.fire_copy(*_passwordState);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_passwordRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::applyPendingReset(const MTPaccount_ResetPasswordResult &data) {
|
||||
if (!_passwordState) {
|
||||
reloadPasswordState();
|
||||
return;
|
||||
}
|
||||
data.match([&](const MTPDaccount_resetPasswordOk &data) {
|
||||
reloadPasswordState();
|
||||
}, [&](const MTPDaccount_resetPasswordRequestedWait &data) {
|
||||
const auto until = data.vuntil_date().v;
|
||||
if (_passwordState->pendingResetDate != until) {
|
||||
_passwordState->pendingResetDate = until;
|
||||
_passwordStateChanges.fire_copy(*_passwordState);
|
||||
}
|
||||
}, [&](const MTPDaccount_resetPasswordFailedWait &data) {
|
||||
});
|
||||
}
|
||||
|
||||
void ApiWrap::clearUnconfirmedPassword() {
|
||||
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
||||
)).done([=](const MTPBool &result) {
|
||||
_passwordRequestId = 0;
|
||||
reloadPasswordState();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_passwordRequestId = 0;
|
||||
reloadPasswordState();
|
||||
}).send();
|
||||
}
|
||||
|
||||
rpl::producer<Core::CloudPasswordState> ApiWrap::passwordState() const {
|
||||
return _passwordState
|
||||
? _passwordStateChanges.events_starting_with_copy(*_passwordState)
|
||||
: (_passwordStateChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
auto ApiWrap::passwordStateCurrent() const
|
||||
-> std::optional<Core::CloudPasswordState> {
|
||||
return _passwordState
|
||||
? base::make_optional(*_passwordState)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
void ApiWrap::reloadContactSignupSilent() {
|
||||
if (_contactSignupSilentRequestId) {
|
||||
return;
|
||||
@@ -4878,176 +4660,6 @@ 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) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
pushPrivacy(key, data.vrules().v);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacyRequestIds.erase(key);
|
||||
}).send();
|
||||
_privacyRequestIds.emplace(key, requestId);
|
||||
}
|
||||
|
||||
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 = _session->data().user(UserId(userId.v));
|
||||
if (!base::contains(never, user)
|
||||
&& !base::contains(always, user)) {
|
||||
always.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueAllowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
always.reserve(always.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = _session->data().chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: _session->data().channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(never, peer)
|
||||
&& !base::contains(always, peer)) {
|
||||
always.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
}, [&](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 = _session->data().user(UserId(userId.v));
|
||||
if (!base::contains(always, user)
|
||||
&& !base::contains(never, user)) {
|
||||
never.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueDisallowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
never.reserve(never.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = _session->data().chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: _session->data().channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(always, peer)
|
||||
&& !base::contains(never, peer)) {
|
||||
never.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
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::reloadBlockedPeers() {
|
||||
if (_blockedPeersRequestId) {
|
||||
return;
|
||||
}
|
||||
_blockedPeersRequestId = request(MTPcontacts_GetBlocked(
|
||||
MTP_int(0),
|
||||
MTP_int(kBlockedFirstSlice)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_blockedPeersRequestId = 0;
|
||||
const auto push = [&](
|
||||
int count,
|
||||
const QVector<MTPPeerBlocked> &list) {
|
||||
auto slice = BlockedPeersSlice();
|
||||
slice.total = std::max(count, list.size());
|
||||
slice.list.reserve(list.size());
|
||||
for (const auto &contact : list) {
|
||||
contact.match([&](const MTPDpeerBlocked &data) {
|
||||
const auto peer = _session->data().peerLoaded(
|
||||
peerFromMTP(data.vpeer_id()));
|
||||
if (peer) {
|
||||
peer->setIsBlocked(true);
|
||||
slice.list.push_back({ peer, data.vdate().v });
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!_blockedPeersSlice || *_blockedPeersSlice != slice) {
|
||||
_blockedPeersSlice = slice;
|
||||
_blockedPeersChanges.fire(std::move(slice));
|
||||
}
|
||||
};
|
||||
result.match([&](const MTPDcontacts_blockedSlice &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
push(data.vcount().v, data.vblocked().v);
|
||||
}, [&](const MTPDcontacts_blocked &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
push(0, data.vblocked().v);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockedPeersRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
auto ApiWrap::blockedPeersSlice() -> rpl::producer<BlockedPeersSlice> {
|
||||
if (!_blockedPeersSlice) {
|
||||
reloadBlockedPeers();
|
||||
}
|
||||
return _blockedPeersSlice
|
||||
? _blockedPeersChanges.events_starting_with_copy(*_blockedPeersSlice)
|
||||
: (_blockedPeersChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
Api::Authorizations &ApiWrap::authorizations() {
|
||||
return *_authorizations;
|
||||
}
|
||||
@@ -5056,6 +4668,14 @@ Api::AttachedStickers &ApiWrap::attachedStickers() {
|
||||
return *_attachedStickers;
|
||||
}
|
||||
|
||||
Api::BlockedPeers &ApiWrap::blockedPeers() {
|
||||
return *_blockedPeers;
|
||||
}
|
||||
|
||||
Api::CloudPassword &ApiWrap::cloudPassword() {
|
||||
return *_cloudPassword;
|
||||
}
|
||||
|
||||
Api::SelfDestruct &ApiWrap::selfDestruct() {
|
||||
return *_selfDestruct;
|
||||
}
|
||||
@@ -5068,6 +4688,10 @@ Api::GlobalPrivacy &ApiWrap::globalPrivacy() {
|
||||
return *_globalPrivacy;
|
||||
}
|
||||
|
||||
Api::UserPrivacy &ApiWrap::userPrivacy() {
|
||||
return *_userPrivacy;
|
||||
}
|
||||
|
||||
Api::InviteLinks &ApiWrap::inviteLinks() {
|
||||
return *_inviteLinks;
|
||||
}
|
||||
|
||||
@@ -45,10 +45,6 @@ namespace Dialogs {
|
||||
class Key;
|
||||
} // namespace Dialogs
|
||||
|
||||
namespace Core {
|
||||
struct CloudPasswordState;
|
||||
} // namespace Core
|
||||
|
||||
namespace Ui {
|
||||
struct PreparedList;
|
||||
} // namespace Ui
|
||||
@@ -58,9 +54,12 @@ namespace Api {
|
||||
class Updates;
|
||||
class Authorizations;
|
||||
class AttachedStickers;
|
||||
class BlockedPeers;
|
||||
class CloudPassword;
|
||||
class SelfDestruct;
|
||||
class SensitiveContent;
|
||||
class GlobalPrivacy;
|
||||
class UserPrivacy;
|
||||
class InviteLinks;
|
||||
|
||||
namespace details {
|
||||
@@ -113,46 +112,6 @@ public:
|
||||
using SendAction = Api::SendAction;
|
||||
using MessageToSend = Api::MessageToSend;
|
||||
|
||||
struct Privacy {
|
||||
enum class Key {
|
||||
PhoneNumber,
|
||||
AddedByPhone,
|
||||
LastSeen,
|
||||
Calls,
|
||||
Invites,
|
||||
CallsPeer2Peer,
|
||||
Forwards,
|
||||
ProfilePhoto,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
Contacts,
|
||||
Nobody,
|
||||
};
|
||||
Option option = Option::Everyone;
|
||||
std::vector<not_null<PeerData*>> always;
|
||||
std::vector<not_null<PeerData*>> never;
|
||||
|
||||
static MTPInputPrivacyKey Input(Key key);
|
||||
static std::optional<Key> KeyFromMTP(mtpTypeId type);
|
||||
};
|
||||
|
||||
struct BlockedPeersSlice {
|
||||
struct Item {
|
||||
PeerData *peer = nullptr;
|
||||
TimeId date = 0;
|
||||
|
||||
bool operator==(const Item &other) const;
|
||||
bool operator!=(const Item &other) const;
|
||||
};
|
||||
|
||||
QVector<Item> list;
|
||||
int total = 0;
|
||||
|
||||
bool operator==(const BlockedPeersSlice &other) const;
|
||||
bool operator!=(const BlockedPeersSlice &other) const;
|
||||
};
|
||||
|
||||
explicit ApiWrap(not_null<Main::Session*> session);
|
||||
~ApiWrap();
|
||||
|
||||
@@ -295,19 +254,10 @@ public:
|
||||
void joinChannel(not_null<ChannelData*> channel);
|
||||
void leaveChannel(not_null<ChannelData*> channel);
|
||||
|
||||
void blockPeer(not_null<PeerData*> peer);
|
||||
void unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone = nullptr);
|
||||
|
||||
void requestNotifySettings(const MTPInputNotifyPeer &peer);
|
||||
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
||||
void saveDraftToCloudDelayed(not_null<History*> history);
|
||||
|
||||
void savePrivacy(
|
||||
const MTPInputPrivacyKey &key,
|
||||
QVector<MTPInputPrivacyRule> &&rules);
|
||||
void handlePrivacyChange(
|
||||
Privacy::Key key,
|
||||
const MTPVector<MTPPrivacyRule> &rules);
|
||||
static int OnlineTillFromStatus(
|
||||
const MTPUserStatus &status,
|
||||
int currentOnlineTill);
|
||||
@@ -433,12 +383,6 @@ public:
|
||||
void uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image);
|
||||
void clearPeerPhoto(not_null<PhotoData*> photo);
|
||||
|
||||
void reloadPasswordState();
|
||||
void applyPendingReset(const MTPaccount_ResetPasswordResult &data);
|
||||
void clearUnconfirmedPassword();
|
||||
rpl::producer<Core::CloudPasswordState> passwordState() const;
|
||||
std::optional<Core::CloudPasswordState> passwordStateCurrent() const;
|
||||
|
||||
void reloadContactSignupSilent();
|
||||
rpl::producer<bool> contactSignupSilent() const;
|
||||
std::optional<bool> contactSignupSilentCurrent() const;
|
||||
@@ -446,17 +390,14 @@ public:
|
||||
|
||||
void saveSelfBio(const QString &text, FnMut<void()> done);
|
||||
|
||||
void reloadPrivacy(Privacy::Key key);
|
||||
rpl::producer<Privacy> privacyValue(Privacy::Key key);
|
||||
|
||||
void reloadBlockedPeers();
|
||||
rpl::producer<BlockedPeersSlice> blockedPeersSlice();
|
||||
|
||||
[[nodiscard]] Api::Authorizations &authorizations();
|
||||
[[nodiscard]] Api::AttachedStickers &attachedStickers();
|
||||
[[nodiscard]] Api::BlockedPeers &blockedPeers();
|
||||
[[nodiscard]] Api::CloudPassword &cloudPassword();
|
||||
[[nodiscard]] Api::SelfDestruct &selfDestruct();
|
||||
[[nodiscard]] Api::SensitiveContent &sensitiveContent();
|
||||
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
|
||||
[[nodiscard]] Api::UserPrivacy &userPrivacy();
|
||||
[[nodiscard]] Api::InviteLinks &inviteLinks();
|
||||
|
||||
void createPoll(
|
||||
@@ -470,6 +411,8 @@ public:
|
||||
void closePoll(not_null<HistoryItem*> item);
|
||||
void reloadPollResults(not_null<HistoryItem*> item);
|
||||
|
||||
void updatePrivacyLastSeens();
|
||||
|
||||
private:
|
||||
struct MessageDataRequest {
|
||||
using Callbacks = QList<RequestMessageDataCallback>;
|
||||
@@ -626,12 +569,6 @@ 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);
|
||||
|
||||
void migrateDone(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<ChannelData*> channel);
|
||||
@@ -676,7 +613,6 @@ private:
|
||||
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
|
||||
|
||||
QMap<ChannelData*, mtpRequestId> _channelAmInRequests;
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
|
||||
base::flat_map<PeerId, mtpRequestId> _notifySettingRequests;
|
||||
base::flat_map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
|
||||
base::Timer _draftsSaveTimer;
|
||||
@@ -701,8 +637,6 @@ private:
|
||||
|
||||
base::flat_map<not_null<EmojiPtr>, StickersByEmoji> _stickersByEmoji;
|
||||
|
||||
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
|
||||
|
||||
mtpRequestId _contactsRequestId = 0;
|
||||
mtpRequestId _contactsStatusesRequestId = 0;
|
||||
|
||||
@@ -765,27 +699,18 @@ private:
|
||||
|
||||
base::flat_map<FullMsgId, not_null<PeerData*>> _peerPhotoUploads;
|
||||
|
||||
mtpRequestId _passwordRequestId = 0;
|
||||
std::unique_ptr<Core::CloudPasswordState> _passwordState;
|
||||
rpl::event_stream<Core::CloudPasswordState> _passwordStateChanges;
|
||||
|
||||
mtpRequestId _saveBioRequestId = 0;
|
||||
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;
|
||||
|
||||
mtpRequestId _blockedPeersRequestId = 0;
|
||||
std::optional<BlockedPeersSlice> _blockedPeersSlice;
|
||||
rpl::event_stream<BlockedPeersSlice> _blockedPeersChanges;
|
||||
|
||||
const std::unique_ptr<Api::Authorizations> _authorizations;
|
||||
const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
|
||||
const std::unique_ptr<Api::BlockedPeers> _blockedPeers;
|
||||
const std::unique_ptr<Api::CloudPassword> _cloudPassword;
|
||||
const std::unique_ptr<Api::SelfDestruct> _selfDestruct;
|
||||
const std::unique_ptr<Api::SensitiveContent> _sensitiveContent;
|
||||
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;
|
||||
const std::unique_ptr<Api::UserPrivacy> _userPrivacy;
|
||||
const std::unique_ptr<Api::InviteLinks> _inviteLinks;
|
||||
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
|
||||
|
||||
@@ -170,63 +170,6 @@ void EditPrivacyBox::editExceptions(
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
QVector<MTPInputPrivacyRule> EditPrivacyBox::collectResult() {
|
||||
const auto collectInputUsers = [](const auto &peers) {
|
||||
auto result = QVector<MTPInputUser>();
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.push_back(user->inputUser);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto collectInputChats = [](const auto &peers) {
|
||||
auto result = QVector<MTPint>(); // #TODO ids
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (!peer->isUser()) {
|
||||
result.push_back(peerToBareMTPInt(peer->id));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
constexpr auto kMaxRules = 3; // allow users, disallow users, option
|
||||
auto result = QVector<MTPInputPrivacyRule>();
|
||||
result.reserve(kMaxRules);
|
||||
if (showExceptionLink(Exception::Always)) {
|
||||
const auto users = collectInputUsers(_value.always);
|
||||
const auto chats = collectInputChats(_value.always);
|
||||
if (!users.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowChatParticipants(MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
if (showExceptionLink(Exception::Never)) {
|
||||
const auto users = collectInputUsers(_value.never);
|
||||
const auto chats = collectInputChats(_value.never);
|
||||
if (!users.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowChatParticipants(MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
result.push_back([&] {
|
||||
switch (_value.option) {
|
||||
case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
|
||||
case Option::Contacts: return MTP_inputPrivacyValueAllowContacts();
|
||||
case Option::Nobody: return MTP_inputPrivacyValueDisallowAll();
|
||||
}
|
||||
Unexpected("Option value in EditPrivacyBox::collectResult.");
|
||||
}());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<not_null<PeerData*>> &EditPrivacyBox::exceptions(Exception exception) {
|
||||
switch (exception) {
|
||||
case Exception::Always: return _value.always;
|
||||
@@ -379,10 +322,13 @@ void EditPrivacyBox::setupContent() {
|
||||
const auto someAreDisallowed = (_value.option != Option::Everyone)
|
||||
|| !_value.never.empty();
|
||||
_controller->confirmSave(someAreDisallowed, crl::guard(this, [=] {
|
||||
_value.ignoreAlways = !showExceptionLink(Exception::Always);
|
||||
_value.ignoreNever = !showExceptionLink(Exception::Never);
|
||||
|
||||
_controller->saveAdditional();
|
||||
_window->session().api().savePrivacy(
|
||||
_controller->apiKey(),
|
||||
collectResult());
|
||||
_window->session().api().userPrivacy().save(
|
||||
_controller->key(),
|
||||
_value);
|
||||
closeBox();
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
|
||||
namespace Ui {
|
||||
class VerticalLayout;
|
||||
@@ -31,15 +31,14 @@ class EditPrivacyBox;
|
||||
|
||||
class EditPrivacyController {
|
||||
public:
|
||||
using Key = ApiWrap::Privacy::Key;
|
||||
using Option = ApiWrap::Privacy::Option;
|
||||
using Key = Api::UserPrivacy::Key;
|
||||
using Option = Api::UserPrivacy::Option;
|
||||
enum class Exception {
|
||||
Always,
|
||||
Never,
|
||||
};
|
||||
|
||||
[[nodiscard]] virtual Key key() = 0;
|
||||
[[nodiscard]] virtual MTPInputPrivacyKey apiKey() = 0;
|
||||
|
||||
[[nodiscard]] virtual rpl::producer<QString> title() = 0;
|
||||
[[nodiscard]] virtual bool hasOption(Option option) {
|
||||
@@ -102,8 +101,8 @@ private:
|
||||
|
||||
class EditPrivacyBox : public Ui::BoxContent {
|
||||
public:
|
||||
using Value = ApiWrap::Privacy;
|
||||
using Option = Value::Option;
|
||||
using Value = Api::UserPrivacy::Rule;
|
||||
using Option = Api::UserPrivacy::Option;
|
||||
using Exception = EditPrivacyController::Exception;
|
||||
|
||||
EditPrivacyBox(
|
||||
@@ -124,7 +123,6 @@ protected:
|
||||
private:
|
||||
bool showExceptionLink(Exception exception) const;
|
||||
void setupContent();
|
||||
QVector<MTPInputPrivacyRule> collectResult();
|
||||
|
||||
Ui::FlatLabel *addLabel(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
|
||||
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/unixtime.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_domain.h"
|
||||
#include "core/application.h"
|
||||
@@ -43,7 +44,7 @@ enum class PasswordErrorType {
|
||||
void SetCloudPassword(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session) {
|
||||
session->api().passwordState(
|
||||
session->api().cloudPassword().state(
|
||||
) | rpl::start_with_next([=] {
|
||||
using namespace Settings;
|
||||
const auto weak = Ui::MakeWeak(box);
|
||||
@@ -103,7 +104,7 @@ void StartPendingReset(
|
||||
const auto weak = Ui::MakeWeak(context.get());
|
||||
session->api().request(MTPaccount_ResetPassword(
|
||||
)).done([=](const MTPaccount_ResetPasswordResult &result) {
|
||||
session->api().applyPendingReset(result);
|
||||
session->api().cloudPassword().applyPendingReset(result);
|
||||
result.match([&](const MTPDaccount_resetPasswordOk &data) {
|
||||
}, [&](const MTPDaccount_resetPasswordRequestedWait &data) {
|
||||
}, [&](const MTPDaccount_resetPasswordFailedWait &data) {
|
||||
|
||||
@@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/unixtime.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -444,7 +445,7 @@ void EditAdminBox::transferOwnership() {
|
||||
? peer()->asChannel()->inputChannel
|
||||
: MTP_inputChannelEmpty();
|
||||
const auto api = &peer()->session().api();
|
||||
api->reloadPasswordState();
|
||||
api->cloudPassword().reload();
|
||||
_checkTransferRequestId = api->request(MTPchannels_EditCreator(
|
||||
channel,
|
||||
MTP_inputUserEmpty(),
|
||||
@@ -495,7 +496,7 @@ void EditAdminBox::transferOwnershipChecked() {
|
||||
}
|
||||
|
||||
void EditAdminBox::requestTransferPassword(not_null<ChannelData*> channel) {
|
||||
peer()->session().api().passwordState(
|
||||
peer()->session().api().cloudPassword().state(
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {
|
||||
|
||||
@@ -378,7 +378,8 @@ void Call::setupOutgoingVideo() {
|
||||
Assert(state == Webrtc::VideoState::Active);
|
||||
if (!_videoCapture) {
|
||||
_videoCapture = _delegate->callGetVideoCapture(
|
||||
_videoCaptureDeviceId);
|
||||
_videoCaptureDeviceId,
|
||||
_videoCaptureIsScreencast);
|
||||
_videoCapture->setOutput(_videoOutgoing->sink());
|
||||
}
|
||||
if (_instance) {
|
||||
@@ -985,7 +986,10 @@ void Call::setCurrentCameraDevice(const QString &deviceId) {
|
||||
if (!_videoCaptureIsScreencast) {
|
||||
_videoCaptureDeviceId = deviceId;
|
||||
if (_videoCapture) {
|
||||
_videoCapture->switchToDevice(deviceId.toStdString());
|
||||
_videoCapture->switchToDevice(deviceId.toStdString(), false);
|
||||
if (_instance) {
|
||||
_instance->sendVideoDeviceUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1042,7 +1046,10 @@ void Call::toggleCameraSharing(bool enabled) {
|
||||
const auto deviceId = Core::App().settings().callVideoInputDeviceId();
|
||||
_videoCaptureDeviceId = deviceId;
|
||||
if (_videoCapture) {
|
||||
_videoCapture->switchToDevice(deviceId.toStdString());
|
||||
_videoCapture->switchToDevice(deviceId.toStdString(), false);
|
||||
if (_instance) {
|
||||
_instance->sendVideoDeviceUpdated();
|
||||
}
|
||||
}
|
||||
_videoOutgoing->setState(Webrtc::VideoState::Active);
|
||||
}), true);
|
||||
@@ -1066,7 +1073,10 @@ void Call::toggleScreenSharing(std::optional<QString> uniqueId) {
|
||||
_videoCaptureIsScreencast = true;
|
||||
_videoCaptureDeviceId = *uniqueId;
|
||||
if (_videoCapture) {
|
||||
_videoCapture->switchToDevice(uniqueId->toStdString());
|
||||
_videoCapture->switchToDevice(uniqueId->toStdString(), true);
|
||||
if (_instance) {
|
||||
_instance->sendVideoDeviceUpdated();
|
||||
}
|
||||
}
|
||||
_videoOutgoing->setState(Webrtc::VideoState::Active);
|
||||
}
|
||||
|
||||
@@ -77,8 +77,10 @@ public:
|
||||
Fn<void()> onSuccess,
|
||||
bool video) = 0;
|
||||
|
||||
virtual auto callGetVideoCapture(const QString &deviceId)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0;
|
||||
virtual auto callGetVideoCapture(
|
||||
const QString &deviceId,
|
||||
bool isScreenCapture)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0;
|
||||
|
||||
virtual ~Delegate() = default;
|
||||
|
||||
|
||||
@@ -64,8 +64,10 @@ public:
|
||||
Fn<void()> onSuccess,
|
||||
bool video) override;
|
||||
void callPlaySound(CallSound sound) override;
|
||||
auto callGetVideoCapture(const QString &deviceId)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
|
||||
auto callGetVideoCapture(
|
||||
const QString &deviceId,
|
||||
bool isScreenCapture)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
|
||||
|
||||
void groupCallFinished(not_null<GroupCall*> call) override;
|
||||
void groupCallFailed(not_null<GroupCall*> call) override;
|
||||
@@ -123,9 +125,11 @@ void Instance::Delegate::callPlaySound(CallSound sound) {
|
||||
}());
|
||||
}
|
||||
|
||||
auto Instance::Delegate::callGetVideoCapture(const QString &deviceId)
|
||||
auto Instance::Delegate::callGetVideoCapture(
|
||||
const QString &deviceId,
|
||||
bool isScreenCapture)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface> {
|
||||
return _instance->getVideoCapture(deviceId);
|
||||
return _instance->getVideoCapture(deviceId, isScreenCapture);
|
||||
}
|
||||
|
||||
void Instance::Delegate::groupCallFinished(not_null<GroupCall*> call) {
|
||||
@@ -159,7 +163,7 @@ void Instance::Delegate::groupCallPlaySound(GroupCallSound sound) {
|
||||
|
||||
auto Instance::Delegate::groupCallGetVideoCapture(const QString &deviceId)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface> {
|
||||
return _instance->getVideoCapture(deviceId);
|
||||
return _instance->getVideoCapture(deviceId, false);
|
||||
}
|
||||
|
||||
FnMut<void()> Instance::Delegate::groupCallAddAsyncWaiter() {
|
||||
@@ -699,12 +703,15 @@ void Instance::requestPermissionOrFail(Platform::PermissionType type, Fn<void()>
|
||||
}
|
||||
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> Instance::getVideoCapture(
|
||||
std::optional<QString> deviceId) {
|
||||
std::optional<QString> deviceId,
|
||||
bool isScreenCapture) {
|
||||
if (auto result = _videoCapture.lock()) {
|
||||
if (deviceId) {
|
||||
result->switchToDevice((deviceId->isEmpty()
|
||||
? Core::App().settings().callVideoInputDeviceId()
|
||||
: *deviceId).toStdString());
|
||||
result->switchToDevice(
|
||||
(deviceId->isEmpty()
|
||||
? Core::App().settings().callVideoInputDeviceId()
|
||||
: *deviceId).toStdString(),
|
||||
isScreenCapture);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@ public:
|
||||
bool minimizeCurrentActiveCall();
|
||||
bool closeCurrentActiveCall();
|
||||
[[nodiscard]] auto getVideoCapture(
|
||||
std::optional<QString> deviceId = std::nullopt)
|
||||
std::optional<QString> deviceId = std::nullopt,
|
||||
bool isScreenCapture = false)
|
||||
-> std::shared_ptr<tgcalls::VideoCaptureInterface>;
|
||||
void requestPermissionsOrFail(Fn<void()> onSuccess, bool video = true);
|
||||
|
||||
|
||||
@@ -654,7 +654,7 @@ void GroupCall::toggleScreenSharing(
|
||||
_screenWithAudio = withAudio;
|
||||
_screenState = Webrtc::VideoState::Active;
|
||||
if (changed && wasSharing && isSharingScreen()) {
|
||||
_screenCapture->switchToDevice(uniqueId->toStdString());
|
||||
_screenCapture->switchToDevice(uniqueId->toStdString(), true);
|
||||
}
|
||||
if (_screenInstance) {
|
||||
_screenInstance->setIsMuted(!withAudio);
|
||||
@@ -1951,7 +1951,7 @@ void GroupCall::setupMediaDevices() {
|
||||
) | rpl::start_with_next([=](QString id) {
|
||||
_cameraInputId = id;
|
||||
if (_cameraCapture) {
|
||||
_cameraCapture->switchToDevice(id.toStdString());
|
||||
_cameraCapture->switchToDevice(id.toStdString(), false);
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
@@ -2064,7 +2064,9 @@ void GroupCall::setupOutgoingVideo() {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
_cameraCapture->switchToDevice(_cameraInputId.toStdString());
|
||||
_cameraCapture->switchToDevice(
|
||||
_cameraInputId.toStdString(),
|
||||
false);
|
||||
}
|
||||
if (_instance) {
|
||||
_instance->setVideoCapture(_cameraCapture);
|
||||
@@ -2131,7 +2133,8 @@ void GroupCall::setupOutgoingVideo() {
|
||||
});
|
||||
} else {
|
||||
_screenCapture->switchToDevice(
|
||||
_screenDeviceId.toStdString());
|
||||
_screenDeviceId.toStdString(),
|
||||
true);
|
||||
}
|
||||
if (_screenInstance) {
|
||||
_screenInstance->setVideoCapture(_screenCapture);
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 2009000;
|
||||
constexpr auto AppVersionStr = "2.9";
|
||||
constexpr auto AppVersion = 2009002;
|
||||
constexpr auto AppVersionStr = "2.9.2";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -1059,6 +1059,7 @@ MessageFlags FlagsFromMTP(MTPDmessage::Flags flags) {
|
||||
| ((flags & MTP::f_via_bot_id) ? Flag::HasViaBot : Flag())
|
||||
| ((flags & MTP::f_reply_to) ? Flag::HasReplyInfo : Flag())
|
||||
| ((flags & MTP::f_reply_markup) ? Flag::HasReplyMarkup : Flag())
|
||||
| ((flags & MTP::f_from_scheduled) ? Flag::IsOrWasScheduled : Flag())
|
||||
| ((flags & MTP::f_views) ? Flag::HasViews : Flag());
|
||||
}
|
||||
|
||||
|
||||
@@ -1086,7 +1086,9 @@ void ComposeControls::initKeyHandler() {
|
||||
auto keyEvent = static_cast<QKeyEvent*>(e.get());
|
||||
const auto key = keyEvent->key();
|
||||
const auto isCtrl = keyEvent->modifiers() == Qt::ControlModifier;
|
||||
const auto hasModifiers = keyEvent->modifiers() != Qt::NoModifier;
|
||||
const auto hasModifiers = (Qt::NoModifier !=
|
||||
(keyEvent->modifiers()
|
||||
& ~(Qt::KeypadModifier | Qt::GroupSwitchModifier)));
|
||||
if (key == Qt::Key_O && isCtrl) {
|
||||
_attachRequests.fire({});
|
||||
return;
|
||||
|
||||
@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/peers/edit_contact_box.h"
|
||||
@@ -393,7 +394,7 @@ void ContactStatus::setupReportHandler(not_null<PeerData*> peer) {
|
||||
_controller->showBackFromStack();
|
||||
});
|
||||
if (const auto user = peer->asUser()) {
|
||||
peer->session().api().blockPeer(user);
|
||||
peer->session().api().blockedPeers().block(user);
|
||||
}
|
||||
const auto text = ((peer->isChat() || peer->isMegagroup())
|
||||
? tr::lng_report_spam_sure_group
|
||||
|
||||
@@ -48,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -647,7 +648,7 @@ void ActionsFiller::addBlockAction(not_null<UserData*> user) {
|
||||
Ui::showPeerHistory(user, ShowAtUnreadMsgId);
|
||||
}
|
||||
} else if (user->isBot()) {
|
||||
user->session().api().blockPeer(user);
|
||||
user->session().api().blockedPeers().block(user);
|
||||
} else {
|
||||
window->show(Box(
|
||||
Window::PeerMenuBlockUserBox,
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_domain.h"
|
||||
#include "main/main_session_settings.h"
|
||||
@@ -120,11 +121,11 @@ Session::Session(
|
||||
}, _lifetime);
|
||||
|
||||
if (_settings->hadLegacyCallsPeerToPeerNobody()) {
|
||||
api().savePrivacy(
|
||||
MTP_inputPrivacyKeyPhoneP2P(),
|
||||
QVector<MTPInputPrivacyRule>(
|
||||
1,
|
||||
MTP_inputPrivacyValueDisallowAll()));
|
||||
api().userPrivacy().save(
|
||||
Api::UserPrivacy::Key::CallsPeer2Peer,
|
||||
Api::UserPrivacy::Rule{
|
||||
.option = Api::UserPrivacy::Option::Nobody
|
||||
});
|
||||
saveSettingsDelayed();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ QByteArray DnsUserAgent() {
|
||||
static const auto kResult = QByteArray(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/91.0.4472.114 Safari/537.36");
|
||||
"Chrome/92.0.4515.107 Safari/537.36");
|
||||
return kResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/core_cloud_password.h" // Core::CloudPasswordState
|
||||
#include "lang/lang_keys.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
@@ -161,7 +162,7 @@ CheckoutProcess::CheckoutProcess(
|
||||
_panel->toggleProgress(true);
|
||||
|
||||
if (mode == Mode::Payment) {
|
||||
_session->api().passwordState(
|
||||
_session->api().cloudPassword().state(
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {
|
||||
_form->setHasPassword(!!state.request);
|
||||
}, _lifetime);
|
||||
@@ -192,7 +193,7 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
|
||||
showForm();
|
||||
}
|
||||
if (_form->paymentMethod().savedCredentials) {
|
||||
_session->api().reloadPasswordState();
|
||||
_session->api().cloudPassword().reload();
|
||||
}
|
||||
}, [&](const ThumbnailUpdated &data) {
|
||||
_panel->updateFormThumbnail(data.thumbnail);
|
||||
@@ -585,7 +586,7 @@ void CheckoutProcess::editPaymentMethod() {
|
||||
}
|
||||
|
||||
void CheckoutProcess::requestSetPassword() {
|
||||
_session->api().reloadPasswordState();
|
||||
_session->api().cloudPassword().reload();
|
||||
_panel->askSetPassword();
|
||||
}
|
||||
|
||||
@@ -622,12 +623,12 @@ void CheckoutProcess::panelSetPassword() {
|
||||
box->newPasswordSet() | rpl::to_empty,
|
||||
box->passwordReloadNeeded()
|
||||
) | rpl::start_with_next([=] {
|
||||
_session->api().reloadPasswordState();
|
||||
_session->api().cloudPassword().reload();
|
||||
}, box->lifetime());
|
||||
|
||||
box->clearUnconfirmedPassword(
|
||||
) | rpl::start_with_next([=] {
|
||||
_session->api().clearUnconfirmedPassword();
|
||||
_session->api().cloudPassword().clearUnconfirmedPassword();
|
||||
}, box->lifetime());
|
||||
|
||||
_panel->showBox(std::move(owned));
|
||||
@@ -645,7 +646,7 @@ void CheckoutProcess::getPasswordState(
|
||||
if (_gettingPasswordState) {
|
||||
return;
|
||||
}
|
||||
_session->api().passwordState(
|
||||
_session->api().cloudPassword().state(
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {
|
||||
_gettingPasswordState.destroy();
|
||||
callback(state);
|
||||
|
||||
@@ -925,6 +925,7 @@ void MainWindow::psSetupTrayIcon() {
|
||||
this);
|
||||
|
||||
_private->sniTrayIcon->setTitle(AppName.utf16());
|
||||
_private->sniTrayIcon->setCategory(qsl("Communications"));
|
||||
_private->sniTrayIcon->setContextMenu(trayIconMenu);
|
||||
_private->setSNITrayIcon(counter, muted);
|
||||
|
||||
|
||||
@@ -287,7 +287,7 @@ bool MainWindow::hasTabletView() const {
|
||||
return (mode == ViewManagement::UserInteractionMode_Touch);
|
||||
}
|
||||
|
||||
bool MainWindow::initSizeFromSystem() {
|
||||
bool MainWindow::initGeometryFromSystem() {
|
||||
if (!hasTabletView()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ protected:
|
||||
|
||||
void workmodeUpdated(Core::Settings::WorkMode mode) override;
|
||||
|
||||
bool initSizeFromSystem() override;
|
||||
bool initGeometryFromSystem() override;
|
||||
|
||||
QRect computeDesktopRect() const override;
|
||||
|
||||
|
||||
@@ -124,7 +124,9 @@ void Calls::setupContent() {
|
||||
call->setCurrentCameraDevice(deviceId);
|
||||
}
|
||||
if (*capturerOwner) {
|
||||
(*capturerOwner)->switchToDevice(deviceId.toStdString());
|
||||
(*capturerOwner)->switchToDevice(
|
||||
deviceId.toStdString(),
|
||||
false);
|
||||
}
|
||||
});
|
||||
_controller->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
@@ -179,7 +181,8 @@ void Calls::setupContent() {
|
||||
return;
|
||||
}
|
||||
*capturerOwner = Core::App().calls().getVideoCapture(
|
||||
Core::App().settings().callVideoInputDeviceId());
|
||||
Core::App().settings().callVideoInputDeviceId(),
|
||||
false);
|
||||
(*capturerOwner)->setPreferredAspectRatio(0.);
|
||||
track->setState(VideoState::Active);
|
||||
(*capturerOwner)->setState(tgcalls::VideoState::Active);
|
||||
|
||||
@@ -31,8 +31,9 @@ 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_cloud_password.h"
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "api/api_sensitive_content.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "core/click_handler_types.h"
|
||||
@@ -378,7 +379,7 @@ void Main::setupContent(not_null<Window::SessionController*> controller) {
|
||||
Ui::ResizeFitChild(this, content);
|
||||
|
||||
// If we load this in advance it won't jump when we open its' section.
|
||||
controller->session().api().reloadPasswordState();
|
||||
controller->session().api().cloudPassword().reload();
|
||||
controller->session().api().reloadContactSignupSilent();
|
||||
controller->session().api().sensitiveContent().reload();
|
||||
controller->session().api().globalPrivacy().reload();
|
||||
|
||||
@@ -45,7 +45,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Settings {
|
||||
namespace {
|
||||
|
||||
constexpr auto kBlockedPerPage = 40;
|
||||
using UserPrivacy = Api::UserPrivacy;
|
||||
using PrivacyRule = Api::UserPrivacy::Rule;
|
||||
|
||||
class BlockPeerBoxController final : public ChatsListBoxController {
|
||||
public:
|
||||
@@ -177,8 +178,7 @@ AdminLog::OwnedItem GenerateForwardedItem(
|
||||
|
||||
BlockedBoxController::BlockedBoxController(
|
||||
not_null<Window::SessionController*> window)
|
||||
: _window(window)
|
||||
, _api(&_window->session().mtp()) {
|
||||
: _window(window) {
|
||||
}
|
||||
|
||||
Main::Session &BlockedBoxController::session() const {
|
||||
@@ -196,52 +196,26 @@ void BlockedBoxController::prepare() {
|
||||
handleBlockedEvent(update.peer);
|
||||
}, lifetime());
|
||||
|
||||
_loadRequestId = -1;
|
||||
_window->session().api().blockedPeersSlice(
|
||||
session().api().blockedPeers().slice(
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const ApiWrap::BlockedPeersSlice &result) {
|
||||
) | rpl::start_with_next([=](const Api::BlockedPeers::Slice &result) {
|
||||
setDescriptionText(tr::lng_blocked_list_about(tr::now));
|
||||
_loadRequestId = 0;
|
||||
_offset = result.list.size();
|
||||
_allLoaded = (_offset >= result.total);
|
||||
for (const auto item : result.list) {
|
||||
appendRow(item.peer);
|
||||
};
|
||||
delegate()->peerListRefreshRows();
|
||||
applySlice(result);
|
||||
loadMoreRows();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void BlockedBoxController::loadMoreRows() {
|
||||
if (_loadRequestId || _allLoaded) {
|
||||
if (_allLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
_loadRequestId = _api.request(MTPcontacts_GetBlocked(
|
||||
MTP_int(_offset),
|
||||
MTP_int(kBlockedPerPage)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_loadRequestId = 0;
|
||||
|
||||
auto handleContactsBlocked = [&](auto &list) {
|
||||
_window->session().data().processUsers(list.vusers());
|
||||
_window->session().data().processChats(list.vchats());
|
||||
return list.vblocked().v;
|
||||
};
|
||||
switch (result.type()) {
|
||||
case mtpc_contacts_blockedSlice: {
|
||||
receivedPeers(handleContactsBlocked(result.c_contacts_blockedSlice()));
|
||||
} break;
|
||||
case mtpc_contacts_blocked: {
|
||||
_allLoaded = true;
|
||||
receivedPeers(handleContactsBlocked(result.c_contacts_blocked()));
|
||||
} break;
|
||||
default: Unexpected("Bad type() in MTPcontacts_GetBlocked() result.");
|
||||
}
|
||||
}).fail([this](const MTP::Error &error) {
|
||||
_loadRequestId = 0;
|
||||
}).send();
|
||||
session().api().blockedPeers().request(
|
||||
_offset,
|
||||
crl::guard(&_guard, [=](const Api::BlockedPeers::Slice &slice) {
|
||||
applySlice(slice);
|
||||
}));
|
||||
}
|
||||
|
||||
void BlockedBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
@@ -252,23 +226,23 @@ void BlockedBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
}
|
||||
|
||||
void BlockedBoxController::rowActionClicked(not_null<PeerListRow*> row) {
|
||||
_window->session().api().unblockPeer(row->peer());
|
||||
session().api().blockedPeers().unblock(row->peer());
|
||||
}
|
||||
|
||||
void BlockedBoxController::receivedPeers(
|
||||
const QVector<MTPPeerBlocked> &result) {
|
||||
if (result.empty()) {
|
||||
void BlockedBoxController::applySlice(const Api::BlockedPeers::Slice &slice) {
|
||||
if (slice.list.empty()) {
|
||||
_allLoaded = true;
|
||||
}
|
||||
|
||||
_offset += result.size();
|
||||
for (const auto &item : result) {
|
||||
item.match([&](const MTPDpeerBlocked &data) {
|
||||
if (const auto peer = _window->session().data().peerLoaded(peerFromMTP(data.vpeer_id()))) {
|
||||
appendRow(peer);
|
||||
peer->setIsBlocked(true);
|
||||
}
|
||||
});
|
||||
_offset += slice.list.size();
|
||||
for (const auto &item : slice.list) {
|
||||
if (const auto peer = session().data().peerLoaded(item.id)) {
|
||||
appendRow(peer);
|
||||
peer->setIsBlocked(true);
|
||||
}
|
||||
}
|
||||
if (_offset >= slice.total) {
|
||||
_allLoaded = true;
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
@@ -292,7 +266,7 @@ void BlockedBoxController::BlockNewPeer(
|
||||
auto initBox = [=, controller = controller.get()](
|
||||
not_null<PeerListBox*> box) {
|
||||
controller->setBlockPeerCallback([=](not_null<PeerData*> peer) {
|
||||
window->session().api().blockPeer(peer);
|
||||
window->session().api().blockedPeers().block(peer);
|
||||
box->closeBox();
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [box] { box->closeBox(); });
|
||||
@@ -339,14 +313,10 @@ std::unique_ptr<PeerListRow> BlockedBoxController::createRow(
|
||||
return row;
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key PhoneNumberPrivacyController::key() {
|
||||
UserPrivacy::Key PhoneNumberPrivacyController::key() {
|
||||
return Key::PhoneNumber;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey PhoneNumberPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyPhoneNumber();
|
||||
}
|
||||
|
||||
rpl::producer<QString> PhoneNumberPrivacyController::title() {
|
||||
return tr::lng_edit_privacy_phone_number_title();
|
||||
}
|
||||
@@ -396,8 +366,8 @@ object_ptr<Ui::RpWidget> PhoneNumberPrivacyController::setupMiddleWidget(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<Option> optionValue) {
|
||||
const auto key = ApiWrap::Privacy::Key::AddedByPhone;
|
||||
controller->session().api().reloadPrivacy(key);
|
||||
const auto key = UserPrivacy::Key::AddedByPhone;
|
||||
controller->session().api().userPrivacy().reload(key);
|
||||
|
||||
_phoneNumberOption = std::move(optionValue);
|
||||
|
||||
@@ -413,11 +383,11 @@ object_ptr<Ui::RpWidget> PhoneNumberPrivacyController::setupMiddleWidget(
|
||||
group->setChangedCallback([=](Option value) {
|
||||
_addedByPhone = value;
|
||||
});
|
||||
controller->session().api().privacyValue(
|
||||
controller->session().api().userPrivacy().value(
|
||||
key
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const ApiWrap::Privacy &value) {
|
||||
) | rpl::start_with_next([=](const PrivacyRule &value) {
|
||||
group->setValue(value.option);
|
||||
}, widget->lifetime());
|
||||
|
||||
@@ -435,15 +405,9 @@ object_ptr<Ui::RpWidget> PhoneNumberPrivacyController::setupMiddleWidget(
|
||||
));
|
||||
|
||||
_saveAdditional = [=] {
|
||||
const auto value = [&] {
|
||||
switch (group->value()) {
|
||||
case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
|
||||
default: return MTP_inputPrivacyValueAllowContacts();
|
||||
}
|
||||
}();
|
||||
controller->session().api().savePrivacy(
|
||||
MTP_inputPrivacyKeyAddedByPhone(),
|
||||
QVector<MTPInputPrivacyRule>(1, value));
|
||||
controller->session().api().userPrivacy().save(
|
||||
Api::UserPrivacy::Key::AddedByPhone,
|
||||
Api::UserPrivacy::Rule{ .option = group->value() });
|
||||
};
|
||||
|
||||
return widget;
|
||||
@@ -460,14 +424,10 @@ LastSeenPrivacyController::LastSeenPrivacyController(
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key LastSeenPrivacyController::key() {
|
||||
UserPrivacy::Key LastSeenPrivacyController::key() {
|
||||
return Key::LastSeen;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey LastSeenPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyStatusTimestamp();
|
||||
}
|
||||
|
||||
rpl::producer<QString> LastSeenPrivacyController::title() {
|
||||
return tr::lng_edit_privacy_lastseen_title();
|
||||
}
|
||||
@@ -528,14 +488,10 @@ void LastSeenPrivacyController::confirmSave(
|
||||
}
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key GroupsInvitePrivacyController::key() {
|
||||
UserPrivacy::Key GroupsInvitePrivacyController::key() {
|
||||
return Key::Invites;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey GroupsInvitePrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyChatInvite();
|
||||
}
|
||||
|
||||
rpl::producer<QString> GroupsInvitePrivacyController::title() {
|
||||
return tr::lng_edit_privacy_groups_title();
|
||||
}
|
||||
@@ -571,14 +527,10 @@ auto GroupsInvitePrivacyController::exceptionsDescription()
|
||||
return tr::lng_edit_privacy_groups_exceptions();
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key CallsPrivacyController::key() {
|
||||
UserPrivacy::Key CallsPrivacyController::key() {
|
||||
return Key::Calls;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey CallsPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyPhoneCall();
|
||||
}
|
||||
|
||||
rpl::producer<QString> CallsPrivacyController::title() {
|
||||
return tr::lng_edit_privacy_calls_title();
|
||||
}
|
||||
@@ -622,21 +574,17 @@ object_ptr<Ui::RpWidget> CallsPrivacyController::setupBelowWidget(
|
||||
controller,
|
||||
content,
|
||||
tr::lng_settings_calls_peer_to_peer_button(),
|
||||
ApiWrap::Privacy::Key::CallsPeer2Peer,
|
||||
UserPrivacy::Key::CallsPeer2Peer,
|
||||
[] { return std::make_unique<CallsPeer2PeerPrivacyController>(); });
|
||||
AddSkip(content);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key CallsPeer2PeerPrivacyController::key() {
|
||||
UserPrivacy::Key CallsPeer2PeerPrivacyController::key() {
|
||||
return Key::CallsPeer2Peer;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey CallsPeer2PeerPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyPhoneP2P();
|
||||
}
|
||||
|
||||
rpl::producer<QString> CallsPeer2PeerPrivacyController::title() {
|
||||
return tr::lng_edit_privacy_calls_p2p_title();
|
||||
}
|
||||
@@ -687,14 +635,10 @@ ForwardsPrivacyController::ForwardsPrivacyController(
|
||||
, _controller(controller) {
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key ForwardsPrivacyController::key() {
|
||||
UserPrivacy::Key ForwardsPrivacyController::key() {
|
||||
return Key::Forwards;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey ForwardsPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyForwards();
|
||||
}
|
||||
|
||||
rpl::producer<QString> ForwardsPrivacyController::title() {
|
||||
return tr::lng_edit_privacy_forwards_title();
|
||||
}
|
||||
@@ -882,14 +826,10 @@ HistoryView::Context ForwardsPrivacyController::elementContext() {
|
||||
return HistoryView::Context::ContactPreview;
|
||||
}
|
||||
|
||||
ApiWrap::Privacy::Key ProfilePhotoPrivacyController::key() {
|
||||
UserPrivacy::Key ProfilePhotoPrivacyController::key() {
|
||||
return Key::ProfilePhoto;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey ProfilePhotoPrivacyController::apiKey() {
|
||||
return MTP_inputPrivacyKeyProfilePhoto();
|
||||
}
|
||||
|
||||
rpl::producer<QString> ProfilePhotoPrivacyController::title() {
|
||||
return tr::lng_edit_privacy_profile_photo_title();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/edit_privacy_box.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
static void BlockNewPeer(not_null<Window::SessionController*> window);
|
||||
|
||||
private:
|
||||
void receivedPeers(const QVector<MTPPeerBlocked> &result);
|
||||
void applySlice(const Api::BlockedPeers::Slice &slice);
|
||||
void handleBlockedEvent(not_null<PeerData*> peer);
|
||||
|
||||
bool appendRow(not_null<PeerData*> peer);
|
||||
@@ -40,12 +40,12 @@ private:
|
||||
std::unique_ptr<PeerListRow> createRow(not_null<PeerData*> peer) const;
|
||||
|
||||
const not_null<Window::SessionController*> _window;
|
||||
MTP::Sender _api;
|
||||
|
||||
int _offset = 0;
|
||||
mtpRequestId _loadRequestId = 0;
|
||||
bool _allLoaded = false;
|
||||
|
||||
base::has_weak_ptr _guard;
|
||||
|
||||
};
|
||||
|
||||
class PhoneNumberPrivacyController : public EditPrivacyController {
|
||||
@@ -54,7 +54,6 @@ public:
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
rpl::producer<QString> optionsTitleKey() override;
|
||||
@@ -86,7 +85,6 @@ public:
|
||||
explicit LastSeenPrivacyController(not_null<::Main::Session*> session);
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
rpl::producer<QString> optionsTitleKey() override;
|
||||
@@ -111,7 +109,6 @@ public:
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
bool hasOption(Option option) override;
|
||||
@@ -129,7 +126,6 @@ public:
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
rpl::producer<QString> optionsTitleKey() override;
|
||||
@@ -150,7 +146,6 @@ public:
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
rpl::producer<QString> optionsTitleKey() override;
|
||||
@@ -174,7 +169,6 @@ public:
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
rpl::producer<QString> optionsTitleKey() override;
|
||||
@@ -208,7 +202,6 @@ public:
|
||||
using Exception = EditPrivacyBox::Exception;
|
||||
|
||||
Key key() override;
|
||||
MTPInputPrivacyKey apiKey() override;
|
||||
|
||||
rpl::producer<QString> title() override;
|
||||
bool hasOption(Option option) override;
|
||||
|
||||
@@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "settings/settings_privacy_security.h"
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_blocked_peers.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"
|
||||
@@ -57,7 +59,7 @@ namespace {
|
||||
|
||||
constexpr auto kUpdateTimeout = 60 * crl::time(1000);
|
||||
|
||||
using Privacy = ApiWrap::Privacy;
|
||||
using Privacy = Api::UserPrivacy;
|
||||
|
||||
QString PrivacyBase(Privacy::Key key, Privacy::Option option) {
|
||||
using Key = Privacy::Key;
|
||||
@@ -86,10 +88,10 @@ QString PrivacyBase(Privacy::Key key, Privacy::Option option) {
|
||||
rpl::producer<QString> PrivacyString(
|
||||
not_null<::Main::Session*> session,
|
||||
Privacy::Key key) {
|
||||
session->api().reloadPrivacy(key);
|
||||
return session->api().privacyValue(
|
||||
session->api().userPrivacy().reload(key);
|
||||
return session->api().userPrivacy().value(
|
||||
key
|
||||
) | rpl::map([=](const Privacy &value) {
|
||||
) | rpl::map([=](const Privacy::Rule &value) {
|
||||
auto add = QStringList();
|
||||
if (const auto never = ExceptionUsersCount(value.never)) {
|
||||
add.push_back("-" + QString::number(never));
|
||||
@@ -107,8 +109,8 @@ rpl::producer<QString> PrivacyString(
|
||||
}
|
||||
|
||||
rpl::producer<int> BlockedPeersCount(not_null<::Main::Session*> session) {
|
||||
return session->api().blockedPeersSlice(
|
||||
) | rpl::map([=](const ApiWrap::BlockedPeersSlice &data) {
|
||||
return session->api().blockedPeers().slice(
|
||||
) | rpl::map([](const Api::BlockedPeers::Slice &data) {
|
||||
return data.total;
|
||||
});
|
||||
}
|
||||
@@ -148,7 +150,7 @@ void SetupPrivacy(
|
||||
std::move(
|
||||
updateTrigger
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().reloadBlockedPeers();
|
||||
session->api().blockedPeers().reload();
|
||||
}, blockedPeers->lifetime());
|
||||
|
||||
using Key = Privacy::Key;
|
||||
@@ -189,7 +191,7 @@ void SetupPrivacy(
|
||||
Key::Invites,
|
||||
[] { return std::make_unique<GroupsInvitePrivacyController>(); });
|
||||
|
||||
session->api().reloadPrivacy(ApiWrap::Privacy::Key::AddedByPhone);
|
||||
session->api().userPrivacy().reload(Api::UserPrivacy::Key::AddedByPhone);
|
||||
|
||||
AddSkip(container, st::settingsPrivacySecurityPadding);
|
||||
AddDividerText(container, tr::lng_settings_group_privacy_about());
|
||||
@@ -331,13 +333,13 @@ void SetupCloudPassword(
|
||||
const auto session = &controller->session();
|
||||
auto has = rpl::single(
|
||||
false
|
||||
) | rpl::then(controller->session().api().passwordState(
|
||||
) | rpl::then(controller->session().api().cloudPassword().state(
|
||||
) | rpl::map([](const State &state) {
|
||||
return state.request
|
||||
|| state.unknownAlgorithm
|
||||
|| !state.unconfirmedPattern.isEmpty();
|
||||
})) | rpl::distinct_until_changed();
|
||||
auto pattern = session->api().passwordState(
|
||||
auto pattern = session->api().cloudPassword().state(
|
||||
) | rpl::map([](const State &state) {
|
||||
return state.unconfirmedPattern;
|
||||
});
|
||||
@@ -360,7 +362,7 @@ void SetupCloudPassword(
|
||||
) | rpl::then(rpl::duplicate(
|
||||
unconfirmed
|
||||
));
|
||||
auto resetAt = session->api().passwordState(
|
||||
auto resetAt = session->api().cloudPassword().state(
|
||||
) | rpl::map([](const State &state) {
|
||||
return state.pendingResetDate;
|
||||
});
|
||||
@@ -426,7 +428,7 @@ void SetupCloudPassword(
|
||||
unconfirmed
|
||||
)))->setDuration(0);
|
||||
confirm->entity()->addClickHandler([=] {
|
||||
const auto state = session->api().passwordStateCurrent();
|
||||
const auto state = session->api().cloudPassword().stateCurrent();
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
@@ -437,13 +439,13 @@ void SetupCloudPassword(
|
||||
std::move(
|
||||
validation.reloadRequests
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().reloadPasswordState();
|
||||
session->api().cloudPassword().reload();
|
||||
}, validation.box->lifetime());
|
||||
|
||||
std::move(
|
||||
validation.cancelRequests
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().clearUnconfirmedPassword();
|
||||
session->api().cloudPassword().clearUnconfirmedPassword();
|
||||
}, validation.box->lifetime());
|
||||
|
||||
controller->show(std::move(validation.box));
|
||||
@@ -550,7 +552,7 @@ void SetupCloudPassword(
|
||||
const auto sent = std::make_shared<mtpRequestId>(0);
|
||||
reset->entity()->addClickHandler([=] {
|
||||
const auto api = &session->api();
|
||||
const auto state = api->passwordStateCurrent();
|
||||
const auto state = api->cloudPassword().stateCurrent();
|
||||
const auto date = state ? state->pendingResetDate : TimeId(0);
|
||||
if (!date || *sent) {
|
||||
return;
|
||||
@@ -558,7 +560,7 @@ void SetupCloudPassword(
|
||||
*sent = api->request(MTPaccount_ResetPassword(
|
||||
)).done([=](const MTPaccount_ResetPasswordResult &result) {
|
||||
*sent = 0;
|
||||
api->applyPendingReset(result);
|
||||
api->cloudPassword().applyPendingReset(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
*sent = 0;
|
||||
}).send();
|
||||
@@ -568,7 +570,7 @@ void SetupCloudPassword(
|
||||
*sent = api->request(MTPaccount_DeclinePasswordReset(
|
||||
)).done([=] {
|
||||
*sent = 0;
|
||||
api->reloadPasswordState();
|
||||
api->cloudPassword().reload();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
*sent = 0;
|
||||
}).send();
|
||||
@@ -596,7 +598,7 @@ void SetupCloudPassword(
|
||||
|
||||
const auto reloadOnActivation = [=](Qt::ApplicationState state) {
|
||||
if (label->toggled() && state == Qt::ApplicationActive) {
|
||||
controller->session().api().reloadPasswordState();
|
||||
controller->session().api().cloudPassword().reload();
|
||||
}
|
||||
};
|
||||
QObject::connect(
|
||||
@@ -605,7 +607,7 @@ void SetupCloudPassword(
|
||||
label,
|
||||
reloadOnActivation);
|
||||
|
||||
session->api().reloadPasswordState();
|
||||
session->api().cloudPassword().reload();
|
||||
|
||||
AddSkip(container);
|
||||
AddDivider(container);
|
||||
@@ -809,7 +811,7 @@ int ExceptionUsersCount(const std::vector<not_null<PeerData*>> &exceptions) {
|
||||
}
|
||||
|
||||
bool CheckEditCloudPassword(not_null<::Main::Session*> session) {
|
||||
const auto current = session->api().passwordStateCurrent();
|
||||
const auto current = session->api().cloudPassword().stateCurrent();
|
||||
Assert(current.has_value());
|
||||
|
||||
if (!current->unknownAlgorithm
|
||||
@@ -821,7 +823,7 @@ bool CheckEditCloudPassword(not_null<::Main::Session*> session) {
|
||||
}
|
||||
|
||||
object_ptr<Ui::BoxContent> EditCloudPasswordBox(not_null<Main::Session*> session) {
|
||||
const auto current = session->api().passwordStateCurrent();
|
||||
const auto current = session->api().cloudPassword().stateCurrent();
|
||||
Assert(current.has_value());
|
||||
|
||||
auto result = Box<PasscodeBox>(
|
||||
@@ -833,12 +835,12 @@ object_ptr<Ui::BoxContent> EditCloudPasswordBox(not_null<Main::Session*> session
|
||||
box->newPasswordSet() | rpl::to_empty,
|
||||
box->passwordReloadNeeded()
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().reloadPasswordState();
|
||||
session->api().cloudPassword().reload();
|
||||
}, box->lifetime());
|
||||
|
||||
box->clearUnconfirmedPassword(
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().clearUnconfirmedPassword();
|
||||
session->api().cloudPassword().clearUnconfirmedPassword();
|
||||
}, box->lifetime());
|
||||
|
||||
return result;
|
||||
@@ -846,11 +848,11 @@ object_ptr<Ui::BoxContent> EditCloudPasswordBox(not_null<Main::Session*> session
|
||||
|
||||
void RemoveCloudPassword(not_null<Window::SessionController*> controller) {
|
||||
const auto session = &controller->session();
|
||||
const auto current = session->api().passwordStateCurrent();
|
||||
const auto current = session->api().cloudPassword().stateCurrent();
|
||||
Assert(current.has_value());
|
||||
|
||||
if (!current->request) {
|
||||
session->api().clearUnconfirmedPassword();
|
||||
session->api().cloudPassword().clearUnconfirmedPassword();
|
||||
return;
|
||||
}
|
||||
auto fields = PasscodeBox::CloudFields::From(*current);
|
||||
@@ -861,12 +863,12 @@ void RemoveCloudPassword(not_null<Window::SessionController*> controller) {
|
||||
box->newPasswordSet() | rpl::to_empty,
|
||||
box->passwordReloadNeeded()
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().reloadPasswordState();
|
||||
session->api().cloudPassword().reload();
|
||||
}, box->lifetime());
|
||||
|
||||
box->clearUnconfirmedPassword(
|
||||
) | rpl::start_with_next([=] {
|
||||
session->api().clearUnconfirmedPassword();
|
||||
session->api().cloudPassword().clearUnconfirmedPassword();
|
||||
}, box->lifetime());
|
||||
|
||||
controller->show(std::move(box));
|
||||
@@ -897,11 +899,11 @@ void AddPrivacyButton(
|
||||
PrivacyString(session, key),
|
||||
st::settingsButton
|
||||
)->addClickHandler([=] {
|
||||
*shower = session->api().privacyValue(
|
||||
*shower = session->api().userPrivacy().value(
|
||||
key
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Privacy &value) {
|
||||
) | rpl::start_with_next([=](const Privacy::Rule &value) {
|
||||
controller->show(
|
||||
Box<EditPrivacyBox>(controller, controllerFactory(), value),
|
||||
Ui::LayerOption::KeepOther);
|
||||
|
||||
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "settings/settings_common.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
|
||||
class EditPrivacyController;
|
||||
|
||||
@@ -30,7 +30,7 @@ void AddPrivacyButton(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
rpl::producer<QString> label,
|
||||
ApiWrap::Privacy::Key key,
|
||||
Api::UserPrivacy::Key key,
|
||||
Fn<std::unique_ptr<EditPrivacyController>()> controllerFactory);
|
||||
|
||||
class PrivacySecurity : public Section {
|
||||
|
||||
@@ -299,7 +299,7 @@ void MainWindow::init() {
|
||||
}
|
||||
refreshTitleWidget();
|
||||
|
||||
initSize();
|
||||
initGeometry();
|
||||
updateUnreadCounter();
|
||||
}
|
||||
|
||||
@@ -426,13 +426,7 @@ void MainWindow::recountGeometryConstraints() {
|
||||
fixOrder();
|
||||
}
|
||||
|
||||
void MainWindow::initSize() {
|
||||
updateMinimumSize();
|
||||
|
||||
if (initSizeFromSystem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Core::WindowPosition MainWindow::positionFromSettings() const {
|
||||
auto position = Core::App().settings().windowPosition();
|
||||
DEBUG_LOG(("Window Pos: Initializing first %1, %2, %3, %4 "
|
||||
"(scale %5%, maximized %6)")
|
||||
@@ -443,16 +437,20 @@ void MainWindow::initSize() {
|
||||
.arg(position.scale)
|
||||
.arg(Logs::b(position.maximized)));
|
||||
|
||||
if (position.scale != 0) {
|
||||
const auto scaleFactor = cScale() / float64(position.scale);
|
||||
position.x *= scaleFactor;
|
||||
position.y *= scaleFactor;
|
||||
position.w *= scaleFactor;
|
||||
position.h *= scaleFactor;
|
||||
if (!position.scale) {
|
||||
return position;
|
||||
}
|
||||
const auto scaleFactor = cScale() / float64(position.scale);
|
||||
position.x *= scaleFactor;
|
||||
position.y *= scaleFactor;
|
||||
position.w *= scaleFactor;
|
||||
position.h *= scaleFactor;
|
||||
return position;
|
||||
}
|
||||
|
||||
QRect MainWindow::countInitialGeometry(Core::WindowPosition position) {
|
||||
const auto primaryScreen = QGuiApplication::primaryScreen();
|
||||
const auto available = primaryScreen
|
||||
const auto primaryAvailable = primaryScreen
|
||||
? primaryScreen->availableGeometry()
|
||||
: QRect(0, 0, st::windowDefaultWidth, st::windowDefaultHeight);
|
||||
const auto initialWidth = Core::Settings::ThirdColumnByDefault()
|
||||
@@ -461,72 +459,119 @@ void MainWindow::initSize() {
|
||||
const auto initialHeight = Core::Settings::ThirdColumnByDefault()
|
||||
? st::windowBigDefaultHeight
|
||||
: st::windowDefaultHeight;
|
||||
auto geometry = QRect(
|
||||
available.x() + std::max(
|
||||
(available.width() - initialWidth) / 2,
|
||||
const auto initial = QRect(
|
||||
primaryAvailable.x() + std::max(
|
||||
(primaryAvailable.width() - initialWidth) / 2,
|
||||
0),
|
||||
available.y() + std::max(
|
||||
(available.height() - initialHeight) / 2,
|
||||
primaryAvailable.y() + std::max(
|
||||
(primaryAvailable.height() - initialHeight) / 2,
|
||||
0),
|
||||
initialWidth,
|
||||
initialHeight);
|
||||
if (position.w && position.h) {
|
||||
for (auto screen : QGuiApplication::screens()) {
|
||||
if (!position.w || !position.h) {
|
||||
return initial;
|
||||
}
|
||||
const auto screen = [&]() -> QScreen* {
|
||||
for (const auto screen : QGuiApplication::screens()) {
|
||||
if (position.moncrc == screenNameChecksum(screen->name())) {
|
||||
auto screenGeometry = screen->geometry();
|
||||
auto availableGeometry = screen->availableGeometry();
|
||||
DEBUG_LOG(("Window Pos: Screen found, screen geometry: %1, %2, %3, %4").arg(screenGeometry.x()).arg(screenGeometry.y()).arg(screenGeometry.width()).arg(screenGeometry.height()));
|
||||
|
||||
const auto x = availableGeometry.x() - screenGeometry.x();
|
||||
const auto y = availableGeometry.y() - screenGeometry.y();
|
||||
const auto w = availableGeometry.width();
|
||||
const auto h = availableGeometry.height();
|
||||
if (w >= st::windowMinWidth && h >= st::windowMinHeight) {
|
||||
if (position.x < x) position.x = x;
|
||||
if (position.y < y) position.y = y;
|
||||
if (position.w > w) position.w = w;
|
||||
if (position.h > h) position.h = h;
|
||||
const auto rightPoint = position.x + position.w;
|
||||
const auto screenRightPoint = x + w;
|
||||
if (rightPoint > screenRightPoint) {
|
||||
const auto distance = rightPoint - screenRightPoint;
|
||||
const auto newXPos = position.x - distance;
|
||||
if (newXPos >= x) {
|
||||
position.x = newXPos;
|
||||
} else {
|
||||
position.x = x;
|
||||
const auto newRightPoint = position.x + position.w;
|
||||
const auto newDistance = newRightPoint - screenRightPoint;
|
||||
position.w -= newDistance;
|
||||
}
|
||||
}
|
||||
const auto bottomPoint = position.y + position.h;
|
||||
const auto screenBottomPoint = y + h;
|
||||
if (bottomPoint > screenBottomPoint) {
|
||||
const auto distance = bottomPoint - screenBottomPoint;
|
||||
const auto newYPos = position.y - distance;
|
||||
if (newYPos >= y) {
|
||||
position.y = newYPos;
|
||||
} else {
|
||||
position.y = y;
|
||||
const auto newBottomPoint = position.y + position.h;
|
||||
const auto newDistance = newBottomPoint - screenBottomPoint;
|
||||
position.h -= newDistance;
|
||||
}
|
||||
}
|
||||
position.x += screenGeometry.x();
|
||||
position.y += screenGeometry.y();
|
||||
if (position.x + st::windowMinWidth <= screenGeometry.x() + screenGeometry.width() &&
|
||||
position.y + st::windowMinHeight <= screenGeometry.y() + screenGeometry.height()) {
|
||||
DEBUG_LOG(("Window Pos: Resulting geometry is %1, %2, %3, %4").arg(position.x).arg(position.y).arg(position.w).arg(position.h));
|
||||
geometry = QRect(position.x, position.y, position.w, position.h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
if (!screen) {
|
||||
return initial;
|
||||
}
|
||||
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height()));
|
||||
const auto frame = [&] {
|
||||
if (!Core::App().settings().nativeWindowFrame()) {
|
||||
return QMargins();
|
||||
}
|
||||
const auto inner = geometry();
|
||||
const auto outer = frameGeometry();
|
||||
return QMargins(
|
||||
inner.x() - outer.x(),
|
||||
inner.y() - outer.y(),
|
||||
outer.x() + outer.width() - inner.x() - inner.width(),
|
||||
outer.y() + outer.height() - inner.y() - inner.height());
|
||||
}();
|
||||
|
||||
const auto screenGeometry = screen->geometry();
|
||||
const auto availableGeometry = screen->availableGeometry();
|
||||
const auto spaceForInner = availableGeometry.marginsRemoved(
|
||||
frame);
|
||||
DEBUG_LOG(("Window Pos: "
|
||||
"Screen found, screen geometry: %1, %2, %3, %4"
|
||||
).arg(screenGeometry.x()
|
||||
).arg(screenGeometry.y()
|
||||
).arg(screenGeometry.width()
|
||||
).arg(screenGeometry.height()));
|
||||
|
||||
const auto x = spaceForInner.x() - screenGeometry.x();
|
||||
const auto y = spaceForInner.y() - screenGeometry.y();
|
||||
const auto w = spaceForInner.width();
|
||||
const auto h = spaceForInner.height();
|
||||
if (w < st::windowMinWidth || h < st::windowMinHeight) {
|
||||
return initial;
|
||||
}
|
||||
if (position.x < x) position.x = x;
|
||||
if (position.y < y) position.y = y;
|
||||
if (position.w > w) position.w = w;
|
||||
if (position.h > h) position.h = h;
|
||||
const auto rightPoint = position.x + position.w;
|
||||
const auto screenRightPoint = x + w;
|
||||
if (rightPoint > screenRightPoint) {
|
||||
const auto distance = rightPoint - screenRightPoint;
|
||||
const auto newXPos = position.x - distance;
|
||||
if (newXPos >= x) {
|
||||
position.x = newXPos;
|
||||
} else {
|
||||
position.x = x;
|
||||
const auto newRightPoint = position.x + position.w;
|
||||
const auto newDistance = newRightPoint - screenRightPoint;
|
||||
position.w -= newDistance;
|
||||
}
|
||||
}
|
||||
const auto bottomPoint = position.y + position.h;
|
||||
const auto screenBottomPoint = y + h;
|
||||
if (bottomPoint > screenBottomPoint) {
|
||||
const auto distance = bottomPoint - screenBottomPoint;
|
||||
const auto newYPos = position.y - distance;
|
||||
if (newYPos >= y) {
|
||||
position.y = newYPos;
|
||||
} else {
|
||||
position.y = y;
|
||||
const auto newBottomPoint = position.y + position.h;
|
||||
const auto newDistance = newBottomPoint - screenBottomPoint;
|
||||
position.h -= newDistance;
|
||||
}
|
||||
}
|
||||
position.x += screenGeometry.x();
|
||||
position.y += screenGeometry.y();
|
||||
if ((position.x + st::windowMinWidth
|
||||
> screenGeometry.x() + screenGeometry.width())
|
||||
|| (position.y + st::windowMinHeight
|
||||
> screenGeometry.y() + screenGeometry.height())) {
|
||||
return initial;
|
||||
}
|
||||
DEBUG_LOG(("Window Pos: Resulting geometry is %1, %2, %3, %4"
|
||||
).arg(position.x
|
||||
).arg(position.y
|
||||
).arg(position.w
|
||||
).arg(position.h));
|
||||
return QRect(position.x, position.y, position.w, position.h);
|
||||
}
|
||||
|
||||
void MainWindow::initGeometry() {
|
||||
updateMinimumSize();
|
||||
if (initGeometryFromSystem()) {
|
||||
return;
|
||||
}
|
||||
const auto geometry = countInitialGeometry(positionFromSettings());
|
||||
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4"
|
||||
).arg(geometry.x()
|
||||
).arg(geometry.y()
|
||||
).arg(geometry.width()
|
||||
).arg(geometry.height()));
|
||||
setGeometry(geometry);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ class BoxContent;
|
||||
class PlainShadow;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Core {
|
||||
struct WindowPosition;
|
||||
} // namespace Core
|
||||
|
||||
namespace Window {
|
||||
|
||||
class Controller;
|
||||
@@ -166,7 +170,7 @@ protected:
|
||||
virtual void createGlobalMenu() {
|
||||
}
|
||||
|
||||
virtual bool initSizeFromSystem() {
|
||||
virtual bool initGeometryFromSystem() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -185,7 +189,10 @@ private:
|
||||
void refreshTitleWidget();
|
||||
void updateMinimumSize();
|
||||
void updatePalette();
|
||||
void initSize();
|
||||
|
||||
[[nodiscard]] Core::WindowPosition positionFromSettings() const;
|
||||
[[nodiscard]] QRect countInitialGeometry(Core::WindowPosition position);
|
||||
void initGeometry();
|
||||
|
||||
bool computeIsActive() const;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
#include "api/api_chat_filters.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
@@ -428,7 +429,7 @@ void Filler::addBlockUser(not_null<UserData*> user) {
|
||||
if (user->isBlocked()) {
|
||||
PeerMenuUnblockUserWithBotRestart(user);
|
||||
} else if (user->isBot()) {
|
||||
user->session().api().blockPeer(user);
|
||||
user->session().api().blockedPeers().block(user);
|
||||
} else {
|
||||
window->show(Box(
|
||||
PeerMenuBlockUserBox,
|
||||
@@ -914,7 +915,7 @@ void PeerMenuBlockUserBox(
|
||||
peer->session().updates().applyUpdates(result);
|
||||
}).send();
|
||||
} else {
|
||||
peer->session().api().blockPeer(peer);
|
||||
peer->session().api().blockedPeers().block(peer);
|
||||
if (reportChecked) {
|
||||
peer->session().api().request(MTPmessages_ReportSpam(
|
||||
peer->input
|
||||
@@ -938,7 +939,7 @@ void PeerMenuBlockUserBox(
|
||||
}
|
||||
|
||||
void PeerMenuUnblockUserWithBotRestart(not_null<UserData*> user) {
|
||||
user->session().api().unblockPeer(user, [=] {
|
||||
user->session().api().blockedPeers().unblock(user, [=] {
|
||||
if (user->isBot() && !user->isSupport()) {
|
||||
user->session().api().sendBotStart(user);
|
||||
}
|
||||
|
||||
2
Telegram/ThirdParty/tgcalls
vendored
2
Telegram/ThirdParty/tgcalls
vendored
Submodule Telegram/ThirdParty/tgcalls updated: 6f2746e04c...81e97fa52e
@@ -1,7 +1,7 @@
|
||||
AppVersion 2009000
|
||||
AppVersion 2009002
|
||||
AppVersionStrMajor 2.9
|
||||
AppVersionStrSmall 2.9
|
||||
AppVersionStr 2.9.0
|
||||
AppVersionStrSmall 2.9.2
|
||||
AppVersionStr 2.9.2
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 2.9
|
||||
AppVersionOriginal 2.9.2
|
||||
|
||||
@@ -109,6 +109,8 @@ PRIVATE
|
||||
platform/darwin/GLVideoViewMac.mm
|
||||
platform/darwin/objc_video_encoder_factory.h
|
||||
platform/darwin/objc_video_encoder_factory.mm
|
||||
platform/darwin/objc_video_decoder_factory.h
|
||||
platform/darwin/objc_video_decoder_factory.mm
|
||||
platform/darwin/TGCMIOCapturer.h
|
||||
platform/darwin/TGCMIOCapturer.m
|
||||
platform/darwin/TGCMIODevice.h
|
||||
@@ -177,19 +179,11 @@ PRIVATE
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_compile_definitions(lib_tgcalls
|
||||
PRIVATE
|
||||
WEBRTC_WIN
|
||||
)
|
||||
elseif (APPLE)
|
||||
target_compile_options(lib_tgcalls
|
||||
PRIVATE
|
||||
-fobjc-arc
|
||||
)
|
||||
target_compile_definitions(lib_tgcalls
|
||||
PRIVATE
|
||||
WEBRTC_MAC
|
||||
)
|
||||
remove_target_sources(lib_tgcalls ${tgcalls_loc}
|
||||
platform/darwin/DesktopCaptureSourceView.h
|
||||
platform/darwin/DesktopCaptureSourceView.mm
|
||||
@@ -212,11 +206,6 @@ elseif (APPLE)
|
||||
platform/tdesktop/VideoCameraCapturer.cpp
|
||||
platform/tdesktop/VideoCameraCapturer.h
|
||||
)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_compile_definitions(lib_tgcalls
|
||||
PRIVATE
|
||||
WEBRTC_LINUX
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
|
||||
Submodule Telegram/lib_ui updated: 3f85ce53d6...024f6fc1a9
Submodule Telegram/lib_waylandshells updated: 7fadd9f54c...59b0ee55a6
Submodule Telegram/lib_webrtc updated: 810973807a...ef49f953f1
Submodule Telegram/lib_webview updated: bf2149e815...e06427c624
@@ -1,3 +1,13 @@
|
||||
2.9.2 (10.08.21)
|
||||
|
||||
- Fix crashes and bugs in scheduled messages.
|
||||
- Fix file sending after a call or voice chat on Windows.
|
||||
- Fix main window title glitches on Windows 7.
|
||||
|
||||
2.9.1 (30.07.21)
|
||||
|
||||
- Fix requesting screencast rights on macOS.
|
||||
|
||||
2.9 (30.07.21)
|
||||
|
||||
- Enable auto-delete in your chats to remove messages after 1 month (also 1 day or 1 week).
|
||||
|
||||
2
cmake
2
cmake
Submodule cmake updated: 6602ed1ea0...24543509c1
@@ -174,7 +174,7 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
|
||||
|
||||
git clone https://github.com/desktop-app/tg_angle.git
|
||||
cd tg_angle
|
||||
git checkout f7b17cd
|
||||
git checkout ec51cc6
|
||||
mkdir out
|
||||
cd out
|
||||
mkdir Debug
|
||||
|
||||
@@ -177,7 +177,7 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
|
||||
|
||||
git clone https://github.com/desktop-app/tg_angle.git
|
||||
cd tg_angle
|
||||
git checkout f7b17cd
|
||||
git checkout ec51cc6
|
||||
mkdir out
|
||||
cd out
|
||||
mkdir Debug
|
||||
|
||||
Reference in New Issue
Block a user