Compare commits

..

16 Commits

Author SHA1 Message Date
John Preston
437d35d8c4 Version 2.9.2: Fix build on macOS. 2021-08-10 19:24:56 +03:00
John Preston
36a5dd8d8b Version 2.9.2: Buffer more audio data.
I hope this fixes #16733.
2021-08-10 16:44:59 +03:00
John Preston
d8e99b4860 Version 2.9.2.
- 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.
2021-08-10 16:10:59 +03:00
John Preston
3cddcaa039 Update submodules. 2021-08-10 16:05:08 +03:00
John Preston
49078e5679 Apply a window title workaround on Windows 7.
Fixes #16785, fixes #16758, fixes #16721.
2021-08-10 15:46:18 +03:00
John Preston
1dec054766 Check if native window frame fits for saved geometry. 2021-08-10 15:46:18 +03:00
John Preston
91ef6f13c8 Use good bitrate for screen capture in calls. 2021-08-10 15:46:18 +03:00
John Preston
73c8f16340 Fix maximized window on Linux, update tg_angle. 2021-08-10 15:46:18 +03:00
23rd
cbad2469db Moved MTP cloud password from ApiWrap to Api::CloudPassword. 2021-08-10 15:46:18 +03:00
23rd
0ae260c6e1 Moved MTP blocked peers from ApiWrap to Api::BlockedPeers. 2021-08-10 15:46:18 +03:00
23rd
221ded6d54 Fixed handle of last message on Up arrow in sections on macOS. 2021-08-10 15:46:18 +03:00
23rd
6f80811ecd Fixed applying server messages as scheduled.
Fixed #16726 and many other problems.
2021-08-10 15:46:18 +03:00
23rd
5bd73bab9b Moved user privacy from ApiWrap to Api::UserPrivacy. 2021-08-10 15:46:18 +03:00
Ilya Fedin
ac86f3e5bd Use Communications category for tray icon
Since tdesktop fits it
2021-08-10 15:42:21 +03:00
GitHub Action
bae6a29326 Update User-Agent for DNS to Chrome 92.0.4515.107. 2021-08-09 10:21:57 +03:00
John Preston
dcf86f55af Version 2.9.1.
- Fix requesting screencast rights on macOS.
2021-07-30 21:28:24 +03:00
54 changed files with 1117 additions and 858 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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"

View File

@@ -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"

View 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

View 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

View File

@@ -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 {

View 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

View 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

View File

@@ -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: {

View 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

View 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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();
}));
});

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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,

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -287,7 +287,7 @@ bool MainWindow::hasTabletView() const {
return (mode == ViewManagement::UserInteractionMode_Touch);
}
bool MainWindow::initSizeFromSystem() {
bool MainWindow::initGeometryFromSystem() {
if (!hasTabletView()) {
return false;
}

View File

@@ -65,7 +65,7 @@ protected:
void workmodeUpdated(Core::Settings::WorkMode mode) override;
bool initSizeFromSystem() override;
bool initGeometryFromSystem() override;
QRect computeDesktopRect() const override;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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")

View File

@@ -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

Submodule cmake updated: 6602ed1ea0...24543509c1

View File

@@ -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

View File

@@ -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