tdesktop/Telegram/SourceFiles/data/data_user.cpp

425 lines
11 KiB
C++
Raw Normal View History

/*
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 "data/data_user.h"
#include "storage/localstorage.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_changes.h"
#include "data/data_peer_bot_command.h"
2022-09-01 05:58:04 +00:00
#include "data/data_emoji_statuses.h"
2022-10-09 11:25:47 +00:00
#include "data/data_user_names.h"
#include "data/notify/data_notify_settings.h"
2020-10-10 09:15:37 +00:00
#include "ui/text/text_options.h"
#include "lang/lang_keys.h"
#include "styles/style_chat.h"
namespace {
2019-03-15 12:09:05 +00:00
// User with hidden last seen stays online in UI for such amount of seconds.
constexpr auto kSetOnlineAfterActivity = TimeId(30);
using UpdateFlag = Data::PeerUpdate::Flag;
} // namespace
BotInfo::BotInfo() : text(st::msgMinWidth) {
}
UserData::UserData(not_null<Data::Session*> owner, PeerId id)
2021-12-01 14:51:18 +00:00
: PeerData(owner, id)
, _flags((id == owner->session().userPeerId()) ? Flag::Self : Flag(0)) {
}
bool UserData::canShareThisContact() const {
return canShareThisContactFast()
|| !owner().findContactPhone(peerToUser(id)).isEmpty();
}
void UserData::setIsContact(bool is) {
const auto status = is
? ContactStatus::Contact
: ContactStatus::NotContact;
if (_contactStatus != status) {
_contactStatus = status;
session().changes().peerUpdated(this, UpdateFlag::IsContact);
}
}
// see Serialize::readPeer as well
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
photo.match([&](const MTPDuserProfilePhoto &data) {
updateUserpic(
data.vphoto_id().v,
data.vdc_id().v,
data.is_has_video());
}, [&](const MTPDuserProfilePhotoEmpty &) {
clearUserpic();
});
}
2022-08-19 12:38:11 +00:00
void UserData::setEmojiStatus(const MTPEmojiStatus &status) {
2022-09-01 05:58:04 +00:00
const auto parsed = Data::ParseEmojiStatus(status);
setEmojiStatus(parsed.id, parsed.until);
2022-08-19 12:38:11 +00:00
}
2022-09-01 05:58:04 +00:00
void UserData::setEmojiStatus(DocumentId emojiStatusId, TimeId until) {
if (_emojiStatusId != emojiStatusId) {
_emojiStatusId = emojiStatusId;
session().changes().peerUpdated(this, UpdateFlag::EmojiStatus);
}
2022-09-01 05:58:04 +00:00
owner().emojiStatuses().registerAutomaticClear(this, until);
}
DocumentId UserData::emojiStatusId() const {
return _emojiStatusId;
}
auto UserData::unavailableReasons() const
-> const std::vector<Data::UnavailableReason> & {
return _unavailableReasons;
}
void UserData::setUnavailableReasons(
std::vector<Data::UnavailableReason> &&reasons) {
if (_unavailableReasons != reasons) {
_unavailableReasons = std::move(reasons);
session().changes().peerUpdated(
this,
UpdateFlag::UnavailableReason);
}
}
void UserData::setCommonChatsCount(int count) {
if (_commonChatsCount != count) {
_commonChatsCount = count;
session().changes().peerUpdated(this, UpdateFlag::CommonChats);
}
}
void UserData::setName(const QString &newFirstName, const QString &newLastName, const QString &newPhoneName, const QString &newUsername) {
bool changeName = !newFirstName.isEmpty() || !newLastName.isEmpty();
QString newFullName;
if (changeName && newFirstName.trimmed().isEmpty()) {
firstName = newLastName;
lastName = QString();
newFullName = firstName;
} else {
if (changeName) {
firstName = newFirstName;
lastName = newLastName;
}
newFullName = lastName.isEmpty() ? firstName : tr::lng_full_name(tr::now, lt_first_name, firstName, lt_last_name, lastName);
}
updateNameDelayed(newFullName, newPhoneName, newUsername);
}
void UserData::setUsernames(const Data::Usernames &newUsernames) {
const auto wasUsername = username();
const auto wasUsernames = usernames();
_username.setUsernames(newUsernames);
const auto nowUsername = username();
const auto nowUsernames = usernames();
session().changes().peerUpdated(
this,
UpdateFlag()
| ((wasUsername != nowUsername)
? UpdateFlag::Username
: UpdateFlag())
| (!ranges::equal(wasUsernames, nowUsernames)
? UpdateFlag::Usernames
: UpdateFlag()));
2022-10-09 11:25:47 +00:00
}
void UserData::setUsername(const QString &username) {
_username.setUsername(username);
}
void UserData::setPhone(const QString &newPhone) {
if (_phone != newPhone) {
_phone = newPhone;
}
}
void UserData::setBotInfoVersion(int version) {
if (version < 0) {
2020-06-10 18:08:17 +00:00
// We don't support bots becoming non-bots.
2022-06-15 19:25:51 +00:00
if (botInfo) {
botInfo->version = -1;
}
} else if (!botInfo) {
botInfo = std::make_unique<BotInfo>();
botInfo->version = version;
2020-06-10 18:08:17 +00:00
owner().userIsBotChanged(this);
} else if (botInfo->version < version) {
if (!botInfo->commands.empty()) {
botInfo->commands.clear();
2020-06-10 18:08:17 +00:00
owner().botCommandsChanged(this);
}
botInfo->description.clear();
botInfo->version = version;
botInfo->inited = false;
}
}
void UserData::setBotInfo(const MTPBotInfo &info) {
switch (info.type()) {
case mtpc_botInfo: {
2019-07-18 08:51:11 +00:00
const auto &d = info.c_botInfo();
2022-04-15 13:32:34 +00:00
if (!isBot()) {
return;
} else if (d.vuser_id() && peerFromUser(*d.vuser_id()) != id) {
2019-07-18 08:51:11 +00:00
return;
}
2022-04-15 13:32:34 +00:00
QString desc = qs(d.vdescription().value_or_empty());
if (botInfo->description != desc) {
botInfo->description = desc;
2019-06-12 13:26:04 +00:00
botInfo->text = Ui::Text::String(st::msgMinWidth);
}
2022-06-14 15:16:18 +00:00
auto commands = d.vcommands()
? ranges::views::all(
d.vcommands()->v
) | ranges::views::transform(
Data::BotCommandFromTL
) | ranges::to_vector
: std::vector<Data::BotCommand>();
const auto changedCommands = !ranges::equal(
botInfo->commands,
commands);
botInfo->commands = std::move(commands);
2022-04-11 08:16:34 +00:00
const auto changedButton = Data::ApplyBotMenuButton(
botInfo.get(),
d.vmenu_button());
botInfo->inited = true;
if (changedCommands || changedButton) {
2020-06-10 18:08:17 +00:00
owner().botCommandsChanged(this);
}
} break;
}
}
void UserData::setNameOrPhone(const QString &newNameOrPhone) {
2022-08-09 11:12:19 +00:00
nameOrPhone = newNameOrPhone;
}
void UserData::madeAction(TimeId when) {
2019-03-12 10:36:33 +00:00
if (isBot() || isServiceUser() || when <= 0) {
return;
} else if (onlineTill <= 0 && -onlineTill < when) {
2019-03-15 12:09:05 +00:00
onlineTill = -when - kSetOnlineAfterActivity;
session().changes().peerUpdated(this, UpdateFlag::OnlineStatus);
} else if (onlineTill > 0 && onlineTill < when + 1) {
2019-03-15 12:09:05 +00:00
onlineTill = when + kSetOnlineAfterActivity;
session().changes().peerUpdated(this, UpdateFlag::OnlineStatus);
}
}
void UserData::setAccessHash(uint64 accessHash) {
if (accessHash == kInaccessibleAccessHashOld) {
_accessHash = 0;
2021-07-08 11:19:12 +00:00
_flags.add(Flag::Deleted);
invalidateEmptyUserpic();
} else {
_accessHash = accessHash;
}
}
2021-12-01 14:51:18 +00:00
void UserData::setFlags(UserDataFlags which) {
if ((which & UserDataFlag::Deleted)
!= (flags() & UserDataFlag::Deleted)) {
invalidateEmptyUserpic();
}
2021-12-01 14:51:18 +00:00
_flags.set((flags() & UserDataFlag::Self)
| (which & ~UserDataFlag::Self));
}
void UserData::addFlags(UserDataFlags which) {
setFlags(flags() | which);
2021-12-01 14:51:18 +00:00
}
void UserData::removeFlags(UserDataFlags which) {
setFlags(flags() & ~which);
2021-12-01 14:51:18 +00:00
}
bool UserData::isVerified() const {
return flags() & UserDataFlag::Verified;
}
bool UserData::isScam() const {
return flags() & UserDataFlag::Scam;
}
bool UserData::isFake() const {
return flags() & UserDataFlag::Fake;
}
bool UserData::isPremium() const {
return flags() & UserDataFlag::Premium;
}
bool UserData::isBotInlineGeo() const {
return flags() & UserDataFlag::BotInlineGeo;
}
bool UserData::isBot() const {
return botInfo != nullptr;
}
bool UserData::isSupport() const {
return flags() & UserDataFlag::Support;
}
bool UserData::isInaccessible() const {
return flags() & UserDataFlag::Deleted;
}
bool UserData::canWrite() const {
// Duplicated in Data::CanWriteValue().
return !isInaccessible() && !isRepliesChat();
}
bool UserData::applyMinPhoto() const {
return !(flags() & UserDataFlag::DiscardMinPhoto);
}
bool UserData::canAddContact() const {
return canShareThisContact() && !isContact();
}
2022-07-03 14:56:12 +00:00
bool UserData::canReceiveGifts() const {
return flags() & UserDataFlag::CanReceiveGifts;
}
bool UserData::canReceiveVoices() const {
return !(flags() & UserDataFlag::VoiceMessagesForbidden);
}
bool UserData::canShareThisContactFast() const {
return !_phone.isEmpty();
}
QString UserData::username() const {
return _username.username();
}
QString UserData::editableUsername() const {
return _username.editableUsername();;
}
2022-10-09 11:25:47 +00:00
const std::vector<QString> &UserData::usernames() const {
return _username.usernames();
2022-10-09 11:25:47 +00:00
}
const QString &UserData::phone() const {
return _phone;
}
UserData::ContactStatus UserData::contactStatus() const {
return _contactStatus;
}
bool UserData::isContact() const {
return (contactStatus() == ContactStatus::Contact);
}
UserData::CallsStatus UserData::callsStatus() const {
return _callsStatus;
}
int UserData::commonChatsCount() const {
return _commonChatsCount;
}
void UserData::setCallsStatus(CallsStatus callsStatus) {
if (callsStatus != _callsStatus) {
_callsStatus = callsStatus;
session().changes().peerUpdated(this, UpdateFlag::HasCalls);
}
}
bool UserData::hasCalls() const {
return (callsStatus() != CallsStatus::Disabled)
&& (callsStatus() != CallsStatus::Unknown);
}
namespace Data {
void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
2019-07-05 13:38:38 +00:00
if (const auto photo = update.vprofile_photo()) {
user->owner().processPhoto(*photo);
}
2021-07-08 14:30:27 +00:00
user->setSettings(update.vsettings());
user->owner().notifySettings().apply(user, update.vnotify_settings());
user->setMessagesTTL(update.vttl_period().value_or_empty());
2019-07-05 13:38:38 +00:00
if (const auto info = update.vbot_info()) {
user->setBotInfo(*info);
} else {
user->setBotInfoVersion(-1);
}
2019-07-05 13:38:38 +00:00
if (const auto pinned = update.vpinned_msg_id()) {
2022-10-28 05:19:27 +00:00
SetTopPinnedMessageId(user, pinned->v);
}
2022-07-03 14:56:12 +00:00
const auto canReceiveGifts = (update.vflags().v
& MTPDuserFull::Flag::f_premium_gifts)
&& update.vpremium_gifts();
2021-07-08 11:19:12 +00:00
using Flag = UserDataFlag;
const auto mask = Flag::Blocked
| Flag::HasPhoneCalls
| Flag::PhoneCallsPrivate
2022-07-03 14:56:12 +00:00
| Flag::CanReceiveGifts
| Flag::CanPinMessages
| Flag::VoiceMessagesForbidden;
2021-07-08 11:19:12 +00:00
user->setFlags((user->flags() & ~mask)
| (update.is_phone_calls_private() ? Flag::PhoneCallsPrivate : Flag())
| (update.is_phone_calls_available() ? Flag::HasPhoneCalls : Flag())
2022-07-03 14:56:12 +00:00
| (canReceiveGifts ? Flag::CanReceiveGifts : Flag())
2021-07-08 11:19:12 +00:00
| (update.is_can_pin_message() ? Flag::CanPinMessages : Flag())
| (update.is_blocked() ? Flag::Blocked : Flag())
| (update.is_voice_messages_forbidden()
? Flag::VoiceMessagesForbidden
: Flag()));
user->setIsBlocked(update.is_blocked());
user->setCallsStatus(update.is_phone_calls_private()
? UserData::CallsStatus::Private
: update.is_phone_calls_available()
? UserData::CallsStatus::Enabled
: UserData::CallsStatus::Disabled);
2019-07-05 13:38:38 +00:00
user->setAbout(qs(update.vabout().value_or_empty()));
user->setCommonChatsCount(update.vcommon_chats_count().v);
user->checkFolder(update.vfolder_id().value_or_empty());
2021-08-25 16:16:50 +00:00
user->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));
if (const auto info = user->botInfo.get()) {
const auto group = update.vbot_group_admin_rights()
? ChatAdminRightsInfo(*update.vbot_group_admin_rights()).flags
: ChatAdminRights();
const auto channel = update.vbot_broadcast_admin_rights()
? ChatAdminRightsInfo(
*update.vbot_broadcast_admin_rights()).flags
: ChatAdminRights();
if (info->groupAdminRights != group
|| info->channelAdminRights != channel) {
info->groupAdminRights = group;
info->channelAdminRights = channel;
user->session().changes().peerUpdated(
user,
Data::PeerUpdate::Flag::Rights);
}
}
user->fullUpdated();
}
} // namespace Data