mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Update API scheme on layer 172.
This commit is contained in:
parent
1cfad14437
commit
6e31993777
22 changed files with 343 additions and 245 deletions
|
@ -515,6 +515,7 @@ PRIVATE
|
||||||
data/data_groups.h
|
data/data_groups.h
|
||||||
data/data_histories.cpp
|
data/data_histories.cpp
|
||||||
data/data_histories.h
|
data/data_histories.h
|
||||||
|
data/data_lastseen_status.h
|
||||||
data/data_location.cpp
|
data/data_location.cpp
|
||||||
data/data_location.h
|
data/data_location.h
|
||||||
data/data_media_rotation.cpp
|
data/data_media_rotation.cpp
|
||||||
|
|
|
@ -141,8 +141,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_status_last_week" = "last seen within a week";
|
"lng_status_last_week" = "last seen within a week";
|
||||||
"lng_status_last_month" = "last seen within a month";
|
"lng_status_last_month" = "last seen within a month";
|
||||||
"lng_status_lastseen_now" = "last seen just now";
|
"lng_status_lastseen_now" = "last seen just now";
|
||||||
"lng_status_lastseen_hidden" = "last seen hidden";
|
"lng_status_lastseen_when" = "when?";
|
||||||
"lng_status_lastseen_show" = "show";
|
|
||||||
"lng_status_lastseen_minutes#one" = "last seen {count} minute ago";
|
"lng_status_lastseen_minutes#one" = "last seen {count} minute ago";
|
||||||
"lng_status_lastseen_minutes#other" = "last seen {count} minutes ago";
|
"lng_status_lastseen_minutes#other" = "last seen {count} minutes ago";
|
||||||
"lng_status_lastseen_hours#one" = "last seen {count} hour ago";
|
"lng_status_lastseen_hours#one" = "last seen {count} hour ago";
|
||||||
|
|
|
@ -161,14 +161,13 @@ bool SendProgressManager::skipRequest(const Key &key) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
|
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
|
||||||
const auto online = user->onlineTill;
|
const auto lastseen = user->lastseen();
|
||||||
if (online == kOnlineRecently) {
|
if (lastseen.isRecently()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (online < 0) {
|
} else if (const auto value = lastseen.onlineTill()) {
|
||||||
return (-online < recently);
|
return (value < recently);
|
||||||
} else {
|
|
||||||
return (online < recently);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendProgressManager::done(mtpRequestId requestId) {
|
void SendProgressManager::done(mtpRequestId requestId) {
|
||||||
|
|
|
@ -944,8 +944,9 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto self = session().user();
|
const auto self = session().user();
|
||||||
self->onlineTill = base::unixtime::now()
|
const auto onlineFor = (config.onlineUpdatePeriod / 1000);
|
||||||
+ (isOnline ? (config.onlineUpdatePeriod / 1000) : -1);
|
self->updateLastseen(Data::LastseenStatus::OnlineTill(
|
||||||
|
base::unixtime::now() + (isOnline ? onlineFor : -1)));
|
||||||
session().changes().peerUpdated(
|
session().changes().peerUpdated(
|
||||||
self,
|
self,
|
||||||
Data::PeerUpdate::Flag::OnlineStatus);
|
Data::PeerUpdate::Flag::OnlineStatus);
|
||||||
|
@ -1852,14 +1853,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
case mtpc_updateUserStatus: {
|
case mtpc_updateUserStatus: {
|
||||||
auto &d = update.c_updateUserStatus();
|
auto &d = update.c_updateUserStatus();
|
||||||
if (const auto user = session().data().userLoaded(d.vuser_id())) {
|
if (const auto user = session().data().userLoaded(d.vuser_id())) {
|
||||||
const auto value = OnlineTillFromMTP(
|
const auto now = LastseenFromMTP(d.vstatus(), user->lastseen());
|
||||||
d.vstatus(),
|
if (user->updateLastseen(now)) {
|
||||||
user->onlineTill);
|
|
||||||
if (user->onlineTill != value) {
|
|
||||||
session().changes().peerUpdated(
|
session().changes().peerUpdated(
|
||||||
user,
|
user,
|
||||||
Data::PeerUpdate::Flag::OnlineStatus);
|
Data::PeerUpdate::Flag::OnlineStatus);
|
||||||
session().data().maybeStopWatchForOffline(user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (UserId(d.vuser_id()) == session().userId()) {
|
if (UserId(d.vuser_id()) == session().userId()) {
|
||||||
|
|
|
@ -1922,25 +1922,28 @@ void ApiWrap::saveDraftToCloudDelayed(not_null<Data::Thread*> thread) {
|
||||||
|
|
||||||
void ApiWrap::updatePrivacyLastSeens() {
|
void ApiWrap::updatePrivacyLastSeens() {
|
||||||
const auto now = base::unixtime::now();
|
const auto now = base::unixtime::now();
|
||||||
_session->data().enumerateUsers([&](UserData *user) {
|
if (!_session->premium()) {
|
||||||
if (user->isSelf() || !user->isLoaded() || user->onlineTill <= 0) {
|
_session->data().enumerateUsers([&](not_null<UserData*> user) {
|
||||||
return;
|
if (user->isSelf()
|
||||||
}
|
|| !user->isLoaded()
|
||||||
|
|| user->lastseen().isHidden()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (user->onlineTill + 3 * 86400 >= now) {
|
const auto till = user->lastseen().onlineTill();
|
||||||
user->onlineTill = kOnlineRecently;
|
user->updateLastseen((till + 3 * 86400 >= now)
|
||||||
} else if (user->onlineTill + 7 * 86400 >= now) {
|
? Data::LastseenStatus::Recently(true)
|
||||||
user->onlineTill = kOnlineLastWeek;
|
: (till + 7 * 86400 >= now)
|
||||||
} else if (user->onlineTill + 30 * 86400 >= now) {
|
? Data::LastseenStatus::WithinWeek(true)
|
||||||
user->onlineTill = kOnlineLastMonth;
|
: (till + 30 * 86400 >= now)
|
||||||
} else {
|
? Data::LastseenStatus::WithinMonth(true)
|
||||||
user->onlineTill = kOnlineEmpty;
|
: Data::LastseenStatus::LongAgo(true));
|
||||||
}
|
session().changes().peerUpdated(
|
||||||
session().changes().peerUpdated(
|
user,
|
||||||
user,
|
Data::PeerUpdate::Flag::OnlineStatus);
|
||||||
Data::PeerUpdate::Flag::OnlineStatus);
|
session().data().maybeStopWatchForOffline(user);
|
||||||
session().data().maybeStopWatchForOffline(user);
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
if (_contactsStatusesRequestId) {
|
if (_contactsStatusesRequestId) {
|
||||||
request(_contactsStatusesRequestId).cancel();
|
request(_contactsStatusesRequestId).cancel();
|
||||||
|
@ -1948,19 +1951,17 @@ void ApiWrap::updatePrivacyLastSeens() {
|
||||||
_contactsStatusesRequestId = request(MTPcontacts_GetStatuses(
|
_contactsStatusesRequestId = request(MTPcontacts_GetStatuses(
|
||||||
)).done([=](const MTPVector<MTPContactStatus> &result) {
|
)).done([=](const MTPVector<MTPContactStatus> &result) {
|
||||||
_contactsStatusesRequestId = 0;
|
_contactsStatusesRequestId = 0;
|
||||||
for (const auto &item : result.v) {
|
for (const auto &status : result.v) {
|
||||||
Assert(item.type() == mtpc_contactStatus);
|
const auto &data = status.data();
|
||||||
auto &data = item.c_contactStatus();
|
const auto userId = UserId(data.vuser_id());
|
||||||
if (auto user = _session->data().userLoaded(data.vuser_id())) {
|
if (const auto user = _session->data().userLoaded(userId)) {
|
||||||
auto value = OnlineTillFromMTP(
|
const auto status = LastseenFromMTP(
|
||||||
data.vstatus(),
|
data.vstatus(),
|
||||||
user->onlineTill);
|
user->lastseen());
|
||||||
if (user->onlineTill != value) {
|
if (user->updateLastseen(status)) {
|
||||||
user->onlineTill = value;
|
|
||||||
session().changes().peerUpdated(
|
session().changes().peerUpdated(
|
||||||
user,
|
user,
|
||||||
Data::PeerUpdate::Flag::OnlineStatus);
|
Data::PeerUpdate::Flag::OnlineStatus);
|
||||||
session().data().maybeStopWatchForOffline(user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,7 +598,9 @@ void ContactsBoxController::sortByOnline() {
|
||||||
const auto now = base::unixtime::now();
|
const auto now = base::unixtime::now();
|
||||||
const auto key = [&](const PeerListRow &row) {
|
const auto key = [&](const PeerListRow &row) {
|
||||||
const auto user = row.peer()->asUser();
|
const auto user = row.peer()->asUser();
|
||||||
return user ? (std::min(user->onlineTill, now) + 1) : TimeId();
|
return user
|
||||||
|
? (std::min(user->lastseen().onlineTill(), now + 1) + 1)
|
||||||
|
: TimeId();
|
||||||
};
|
};
|
||||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||||
return key(a) > key(b);
|
return key(a) > key(b);
|
||||||
|
|
|
@ -143,7 +143,7 @@ void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
|
||||||
? tr::lng_status_bot_reads_all
|
? tr::lng_status_bot_reads_all
|
||||||
: tr::lng_status_bot_not_reads_all)(tr::now);
|
: tr::lng_status_bot_not_reads_all)(tr::now);
|
||||||
}
|
}
|
||||||
return Data::OnlineText(_user->onlineTill, base::unixtime::now());
|
return Data::OnlineText(_user->lastseen(), base::unixtime::now());
|
||||||
}();
|
}();
|
||||||
p.setFont(st::contactsStatusFont);
|
p.setFont(st::contactsStatusFont);
|
||||||
p.setPen(st::contactsStatusFg);
|
p.setPen(st::contactsStatusFg);
|
||||||
|
|
131
Telegram/SourceFiles/data/data_lastseen_status.h
Normal file
131
Telegram/SourceFiles/data/data_lastseen_status.h
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
inline constexpr auto kLifeStartDate = 1375315200; // Let it be 01.08.2013.
|
||||||
|
|
||||||
|
class LastseenStatus final {
|
||||||
|
public:
|
||||||
|
LastseenStatus() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] static LastseenStatus Recently(bool byMe = false) {
|
||||||
|
return LastseenStatus(kRecentlyValue, false, byMe);
|
||||||
|
}
|
||||||
|
[[nodiscard]] static LastseenStatus WithinWeek(bool byMe = false) {
|
||||||
|
return LastseenStatus(kWithinWeekValue, false, byMe);
|
||||||
|
}
|
||||||
|
[[nodiscard]] static LastseenStatus WithinMonth(bool byMe = false) {
|
||||||
|
return LastseenStatus(kWithinMonthValue, false, byMe);
|
||||||
|
}
|
||||||
|
[[nodiscard]] static LastseenStatus LongAgo(bool byMe = false) {
|
||||||
|
return LastseenStatus(kLongAgoValue, false, byMe);
|
||||||
|
}
|
||||||
|
[[nodiscard]] static LastseenStatus OnlineTill(
|
||||||
|
TimeId till,
|
||||||
|
bool local = false,
|
||||||
|
bool hiddenByMe = false) {
|
||||||
|
return (till >= kLifeStartDate + kSpecialValueSkip)
|
||||||
|
? LastseenStatus(till - kLifeStartDate, !local, hiddenByMe)
|
||||||
|
: LongAgo(hiddenByMe);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isHidden() const {
|
||||||
|
return !_available;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool isRecently() const {
|
||||||
|
return !_available && (_value == kRecentlyValue);
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool isWithinWeek() const {
|
||||||
|
return !_available && (_value == kWithinWeekValue);
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool isWithinMonth() const {
|
||||||
|
return !_available && (_value == kWithinMonthValue);
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool isLongAgo() const {
|
||||||
|
return !_available && (_value == kLongAgoValue);
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool isHiddenByMe() const {
|
||||||
|
return _hiddenByMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isOnline(TimeId now) const {
|
||||||
|
return (_value >= kSpecialValueSkip)
|
||||||
|
&& (kLifeStartDate + _value > now);
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool isLocalOnlineValue() const {
|
||||||
|
return !_available && (_value >= kSpecialValueSkip);
|
||||||
|
}
|
||||||
|
[[nodiscard]] TimeId onlineTill() const {
|
||||||
|
return (_value >= kSpecialValueSkip)
|
||||||
|
? (kLifeStartDate + _value)
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] uint32 serialize() const {
|
||||||
|
return (_value & 0x3FFFFFFF)
|
||||||
|
| (_available << 30)
|
||||||
|
| (_hiddenByMe << 31);
|
||||||
|
}
|
||||||
|
[[nodiscard]] static LastseenStatus FromSerialized(uint32 value) {
|
||||||
|
auto result = LastseenStatus();
|
||||||
|
result._value = value & 0x3FFFFFFF;
|
||||||
|
result._available = (value >> 30) & 1;
|
||||||
|
result._hiddenByMe = (value >> 31) & 1;
|
||||||
|
return result.valid() ? result : LastseenStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static LastseenStatus FromLegacy(int32 value) {
|
||||||
|
auto result = LastseenStatus();
|
||||||
|
if (value == -2) {
|
||||||
|
return LastseenStatus::Recently();
|
||||||
|
} else if (value == -3) {
|
||||||
|
return LastseenStatus::WithinWeek();
|
||||||
|
} else if (value == -4) {
|
||||||
|
return LastseenStatus::WithinMonth();
|
||||||
|
} else if (value < -30) {
|
||||||
|
return LastseenStatus::OnlineTill(-value, true);
|
||||||
|
} else if (value > 0) {
|
||||||
|
return LastseenStatus::OnlineTill(value);
|
||||||
|
}
|
||||||
|
return LastseenStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline constexpr auto operator<=>(
|
||||||
|
LastseenStatus,
|
||||||
|
LastseenStatus) = default;
|
||||||
|
friend inline constexpr bool operator==(
|
||||||
|
LastseenStatus a,
|
||||||
|
LastseenStatus b) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr auto kLongAgoValue = uint32(0);
|
||||||
|
static constexpr auto kRecentlyValue = uint32(1);
|
||||||
|
static constexpr auto kWithinWeekValue = uint32(2);
|
||||||
|
static constexpr auto kWithinMonthValue = uint32(3);
|
||||||
|
static constexpr auto kSpecialValueSkip = uint32(4);
|
||||||
|
static constexpr auto kValidAfter = kLifeStartDate + kSpecialValueSkip;
|
||||||
|
|
||||||
|
[[nodiscard]] bool valid() const {
|
||||||
|
return !_available || (_value >= kSpecialValueSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastseenStatus(uint32 value, bool available, bool hiddenByMe)
|
||||||
|
: _value(value)
|
||||||
|
, _available(available ? 1 : 0)
|
||||||
|
, _hiddenByMe(hiddenByMe ? 1 : 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 _value : 30 = 0;
|
||||||
|
uint32 _available : 1 = 0;
|
||||||
|
uint32 _hiddenByMe : 1 = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Data
|
|
@ -28,23 +28,20 @@ constexpr auto kMinOnlineChangeTimeout = crl::time(1000);
|
||||||
constexpr auto kMaxOnlineChangeTimeout = 86400 * crl::time(1000);
|
constexpr auto kMaxOnlineChangeTimeout = 86400 * crl::time(1000);
|
||||||
constexpr auto kSecondsInDay = 86400;
|
constexpr auto kSecondsInDay = 86400;
|
||||||
|
|
||||||
int OnlinePhraseChangeInSeconds(TimeId online, TimeId now) {
|
int OnlinePhraseChangeInSeconds(LastseenStatus status, TimeId now) {
|
||||||
if (online <= 0) {
|
const auto till = status.onlineTill();
|
||||||
if (-online > now) {
|
if (till > now) {
|
||||||
return (-online - now);
|
return till - now;
|
||||||
}
|
} else if (status.isHidden()) {
|
||||||
return std::numeric_limits<TimeId>::max();
|
return std::numeric_limits<int>::max();
|
||||||
}
|
}
|
||||||
if (online > now) {
|
const auto minutes = (now - till) / 60;
|
||||||
return online - now;
|
|
||||||
}
|
|
||||||
const auto minutes = (now - online) / 60;
|
|
||||||
if (minutes < 60) {
|
if (minutes < 60) {
|
||||||
return (minutes + 1) * 60 - (now - online);
|
return (minutes + 1) * 60 - (now - till);
|
||||||
}
|
}
|
||||||
const auto hours = (now - online) / 3600;
|
const auto hours = (now - till) / 3600;
|
||||||
if (hours < 12) {
|
if (hours < 12) {
|
||||||
return (hours + 1) * 3600 - (now - online);
|
return (hours + 1) * 3600 - (now - till);
|
||||||
}
|
}
|
||||||
const auto nowFull = base::unixtime::parse(now);
|
const auto nowFull = base::unixtime::parse(now);
|
||||||
const auto tomorrow = nowFull.date().addDays(1).startOfDay();
|
const auto tomorrow = nowFull.date().addDays(1).startOfDay();
|
||||||
|
@ -64,20 +61,17 @@ std::optional<QString> OnlineTextSpecial(not_null<UserData*> user) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QString> OnlineTextCommon(TimeId online, TimeId now) {
|
std::optional<QString> OnlineTextCommon(LastseenStatus status, TimeId now) {
|
||||||
if (online <= 0) {
|
if (status.isOnline(now)) {
|
||||||
switch (online) {
|
|
||||||
case kOnlineEmpty: return tr::lng_status_offline(tr::now);
|
|
||||||
case kOnlineRecently: return tr::lng_status_recently(tr::now);
|
|
||||||
case kOnlineLastWeek: return tr::lng_status_last_week(tr::now);
|
|
||||||
case kOnlineLastMonth: return tr::lng_status_last_month(tr::now);
|
|
||||||
case kOnlineHidden: return tr::lng_status_lastseen_hidden(tr::now);
|
|
||||||
}
|
|
||||||
return IsRecentOnline(online, now)
|
|
||||||
? tr::lng_status_online(tr::now)
|
|
||||||
: tr::lng_status_recently(tr::now);
|
|
||||||
} else if (online > now) {
|
|
||||||
return tr::lng_status_online(tr::now);
|
return tr::lng_status_online(tr::now);
|
||||||
|
} else if (status.isLongAgo()) {
|
||||||
|
return tr::lng_status_offline(tr::now);
|
||||||
|
} else if (status.isRecently()) {
|
||||||
|
return tr::lng_status_recently(tr::now);
|
||||||
|
} else if (status.isWithinWeek()) {
|
||||||
|
return tr::lng_status_last_week(tr::now);
|
||||||
|
} else if (status.isWithinMonth()) {
|
||||||
|
return tr::lng_status_last_month(tr::now);
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -395,31 +389,22 @@ TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now) {
|
||||||
if (user->isServiceUser() || user->isBot()) {
|
if (user->isServiceUser() || user->isBot()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
const auto online = user->onlineTill;
|
const auto lastseen = user->lastseen();
|
||||||
if (online <= 0) {
|
if (const auto till = lastseen.onlineTill()) {
|
||||||
switch (online) {
|
return till;
|
||||||
case 0:
|
} else if (lastseen.isRecently()) {
|
||||||
case -1: return online;
|
return now - 3 * kSecondsInDay;
|
||||||
|
} else if (lastseen.isWithinWeek()) {
|
||||||
case -2: {
|
return now - 7 * kSecondsInDay;
|
||||||
return now - 3 * kSecondsInDay;
|
} else if (lastseen.isWithinMonth()) {
|
||||||
} break;
|
return now - 30 * kSecondsInDay;
|
||||||
|
} else {
|
||||||
case -3: {
|
return 0;
|
||||||
return now - 7 * kSecondsInDay;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case -4: {
|
|
||||||
return now - 30 * kSecondsInDay;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
return -online;
|
|
||||||
}
|
}
|
||||||
return online;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crl::time OnlineChangeTimeout(TimeId online, TimeId now) {
|
crl::time OnlineChangeTimeout(Data::LastseenStatus status, TimeId now) {
|
||||||
const auto result = OnlinePhraseChangeInSeconds(online, now);
|
const auto result = OnlinePhraseChangeInSeconds(status, now);
|
||||||
Assert(result >= 0);
|
Assert(result >= 0);
|
||||||
return std::clamp(
|
return std::clamp(
|
||||||
result * crl::time(1000),
|
result * crl::time(1000),
|
||||||
|
@ -431,24 +416,26 @@ crl::time OnlineChangeTimeout(not_null<UserData*> user, TimeId now) {
|
||||||
if (user->isServiceUser() || user->isBot()) {
|
if (user->isServiceUser() || user->isBot()) {
|
||||||
return kMaxOnlineChangeTimeout;
|
return kMaxOnlineChangeTimeout;
|
||||||
}
|
}
|
||||||
return OnlineChangeTimeout(user->onlineTill, now);
|
return OnlineChangeTimeout(user->lastseen(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OnlineText(TimeId online, TimeId now) {
|
QString OnlineText(Data::LastseenStatus status, TimeId now) {
|
||||||
if (const auto common = OnlineTextCommon(online, now)) {
|
if (const auto common = OnlineTextCommon(status, now)) {
|
||||||
return *common;
|
return *common;
|
||||||
}
|
}
|
||||||
const auto minutes = (now - online) / 60;
|
const auto till = status.onlineTill();
|
||||||
|
Assert(till > 0);
|
||||||
|
const auto minutes = (now - till) / 60;
|
||||||
if (!minutes) {
|
if (!minutes) {
|
||||||
return tr::lng_status_lastseen_now(tr::now);
|
return tr::lng_status_lastseen_now(tr::now);
|
||||||
} else if (minutes < 60) {
|
} else if (minutes < 60) {
|
||||||
return tr::lng_status_lastseen_minutes(tr::now, lt_count, minutes);
|
return tr::lng_status_lastseen_minutes(tr::now, lt_count, minutes);
|
||||||
}
|
}
|
||||||
const auto hours = (now - online) / 3600;
|
const auto hours = (now - till) / 3600;
|
||||||
if (hours < 12) {
|
if (hours < 12) {
|
||||||
return tr::lng_status_lastseen_hours(tr::now, lt_count, hours);
|
return tr::lng_status_lastseen_hours(tr::now, lt_count, hours);
|
||||||
}
|
}
|
||||||
const auto onlineFull = base::unixtime::parse(online);
|
const auto onlineFull = base::unixtime::parse(till);
|
||||||
const auto nowFull = base::unixtime::parse(now);
|
const auto nowFull = base::unixtime::parse(now);
|
||||||
const auto locale = QLocale();
|
const auto locale = QLocale();
|
||||||
if (onlineFull.date() == nowFull.date()) {
|
if (onlineFull.date() == nowFull.date()) {
|
||||||
|
@ -466,16 +453,17 @@ QString OnlineText(not_null<UserData*> user, TimeId now) {
|
||||||
if (const auto special = OnlineTextSpecial(user)) {
|
if (const auto special = OnlineTextSpecial(user)) {
|
||||||
return *special;
|
return *special;
|
||||||
}
|
}
|
||||||
return OnlineText(user->onlineTill, now);
|
return OnlineText(user->lastseen(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OnlineTextFull(not_null<UserData*> user, TimeId now) {
|
QString OnlineTextFull(not_null<UserData*> user, TimeId now) {
|
||||||
if (const auto special = OnlineTextSpecial(user)) {
|
if (const auto special = OnlineTextSpecial(user)) {
|
||||||
return *special;
|
return *special;
|
||||||
} else if (const auto common = OnlineTextCommon(user->onlineTill, now)) {
|
} else if (const auto common = OnlineTextCommon(user->lastseen(), now)) {
|
||||||
return *common;
|
return *common;
|
||||||
}
|
}
|
||||||
const auto onlineFull = base::unixtime::parse(user->onlineTill);
|
const auto till = user->lastseen().onlineTill();
|
||||||
|
const auto onlineFull = base::unixtime::parse(till);
|
||||||
const auto nowFull = base::unixtime::parse(now);
|
const auto nowFull = base::unixtime::parse(now);
|
||||||
const auto locale = QLocale();
|
const auto locale = QLocale();
|
||||||
if (onlineFull.date() == nowFull.date()) {
|
if (onlineFull.date() == nowFull.date()) {
|
||||||
|
@ -490,25 +478,10 @@ QString OnlineTextFull(not_null<UserData*> user, TimeId now) {
|
||||||
return tr::lng_status_lastseen_date_time(tr::now, lt_date, date, lt_time, time);
|
return tr::lng_status_lastseen_date_time(tr::now, lt_date, date, lt_time, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnlineTextActive(TimeId online, TimeId now) {
|
|
||||||
if (online <= 0) {
|
|
||||||
switch (online) {
|
|
||||||
case 0:
|
|
||||||
case -1:
|
|
||||||
case -2:
|
|
||||||
case -3:
|
|
||||||
case -4: return false;
|
|
||||||
}
|
|
||||||
return (-online > now);
|
|
||||||
}
|
|
||||||
return (online > now);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OnlineTextActive(not_null<UserData*> user, TimeId now) {
|
bool OnlineTextActive(not_null<UserData*> user, TimeId now) {
|
||||||
if (user->isServiceUser() || user->isBot()) {
|
return !user->isServiceUser()
|
||||||
return false;
|
&& !user->isBot()
|
||||||
}
|
&& user->lastseen().isOnline(now);
|
||||||
return OnlineTextActive(user->onlineTill, now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsUserOnline(not_null<UserData*> user, TimeId now) {
|
bool IsUserOnline(not_null<UserData*> user, TimeId now) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Data {
|
||||||
|
|
||||||
struct Reaction;
|
struct Reaction;
|
||||||
class ForumTopic;
|
class ForumTopic;
|
||||||
|
class LastseenStatus;
|
||||||
|
|
||||||
template <typename ChangeType, typename Error, typename Generator>
|
template <typename ChangeType, typename Error, typename Generator>
|
||||||
inline auto FlagsValueWithMask(
|
inline auto FlagsValueWithMask(
|
||||||
|
@ -151,14 +152,15 @@ inline auto PeerFullFlagValue(
|
||||||
not_null<Main::Session*> session);
|
not_null<Main::Session*> session);
|
||||||
|
|
||||||
[[nodiscard]] TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
[[nodiscard]] TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
||||||
[[nodiscard]] crl::time OnlineChangeTimeout(TimeId online, TimeId now);
|
[[nodiscard]] crl::time OnlineChangeTimeout(
|
||||||
|
LastseenStatus status,
|
||||||
|
TimeId now);
|
||||||
[[nodiscard]] crl::time OnlineChangeTimeout(
|
[[nodiscard]] crl::time OnlineChangeTimeout(
|
||||||
not_null<UserData*> user,
|
not_null<UserData*> user,
|
||||||
TimeId now);
|
TimeId now);
|
||||||
[[nodiscard]] QString OnlineText(TimeId online, TimeId now);
|
[[nodiscard]] QString OnlineText(LastseenStatus status, TimeId now);
|
||||||
[[nodiscard]] QString OnlineText(not_null<UserData*> user, TimeId now);
|
[[nodiscard]] QString OnlineText(not_null<UserData*> user, TimeId now);
|
||||||
[[nodiscard]] QString OnlineTextFull(not_null<UserData*> user, TimeId now);
|
[[nodiscard]] QString OnlineTextFull(not_null<UserData*> user, TimeId now);
|
||||||
[[nodiscard]] bool OnlineTextActive(TimeId online, TimeId now);
|
|
||||||
[[nodiscard]] bool OnlineTextActive(not_null<UserData*> user, TimeId now);
|
[[nodiscard]] bool OnlineTextActive(not_null<UserData*> user, TimeId now);
|
||||||
[[nodiscard]] bool IsUserOnline(not_null<UserData*> user, TimeId now = 0);
|
[[nodiscard]] bool IsUserOnline(not_null<UserData*> user, TimeId now = 0);
|
||||||
[[nodiscard]] bool ChannelHasActiveCall(not_null<ChannelData*> channel);
|
[[nodiscard]] bool ChannelHasActiveCall(not_null<ChannelData*> channel);
|
||||||
|
|
|
@ -731,11 +731,9 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status && !minimal) {
|
if (status && !minimal) {
|
||||||
const auto value = OnlineTillFromMTP(*status, result->onlineTill);
|
const auto lastseen = LastseenFromMTP(*status, result->lastseen());
|
||||||
if (result->onlineTill != value) {
|
if (result->updateLastseen(lastseen)) {
|
||||||
result->onlineTill = value;
|
|
||||||
flags |= UpdateFlag::OnlineStatus;
|
flags |= UpdateFlag::OnlineStatus;
|
||||||
session().data().maybeStopWatchForOffline(result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1106,7 +1104,8 @@ void Session::watchForOffline(not_null<UserData*> user, TimeId now) {
|
||||||
if (!Data::IsUserOnline(user, now)) {
|
if (!Data::IsUserOnline(user, now)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto till = user->onlineTill;
|
const auto lastseen = user->lastseen();
|
||||||
|
const auto till = lastseen.onlineTill();
|
||||||
const auto &[i, ok] = _watchingForOffline.emplace(user, till);
|
const auto &[i, ok] = _watchingForOffline.emplace(user, till);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
if (i->second == till) {
|
if (i->second == till) {
|
||||||
|
@ -1114,7 +1113,7 @@ void Session::watchForOffline(not_null<UserData*> user, TimeId now) {
|
||||||
}
|
}
|
||||||
i->second = till;
|
i->second = till;
|
||||||
}
|
}
|
||||||
const auto timeout = Data::OnlineChangeTimeout(till, now);
|
const auto timeout = Data::OnlineChangeTimeout(lastseen, now);
|
||||||
const auto fires = _watchForOfflineTimer.isActive()
|
const auto fires = _watchForOfflineTimer.isActive()
|
||||||
? _watchForOfflineTimer.remainingTime()
|
? _watchForOfflineTimer.remainingTime()
|
||||||
: -1;
|
: -1;
|
||||||
|
@ -4397,7 +4396,7 @@ void Session::serviceNotification(
|
||||||
MTPstring(), // username
|
MTPstring(), // username
|
||||||
MTP_string("42777"),
|
MTP_string("42777"),
|
||||||
MTP_userProfilePhotoEmpty(),
|
MTP_userProfilePhotoEmpty(),
|
||||||
MTP_userStatusRecently(),
|
MTP_userStatusRecently(MTP_flags(0)),
|
||||||
MTPint(), // bot_info_version
|
MTPint(), // bot_info_version
|
||||||
MTPVector<MTPRestrictionReason>(),
|
MTPVector<MTPRestrictionReason>(),
|
||||||
MTPstring(), // bot_inline_placeholder
|
MTPstring(), // bot_inline_placeholder
|
||||||
|
|
|
@ -34,37 +34,26 @@ using UpdateFlag = Data::PeerUpdate::Flag;
|
||||||
|
|
||||||
BotInfo::BotInfo() = default;
|
BotInfo::BotInfo() = default;
|
||||||
|
|
||||||
int RecentOnlineAfter(TimeId when) {
|
Data::LastseenStatus LastseenFromMTP(
|
||||||
return (when > 0) ? (-when - kSetOnlineAfterActivity) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsRecentOnlineValue(int value) {
|
|
||||||
return (value < -kSetOnlineAfterActivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsRecentOnline(int value, TimeId now) {
|
|
||||||
return IsRecentOnlineValue(value) && (now < -value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int OnlineTillFromMTP(
|
|
||||||
const MTPUserStatus &status,
|
const MTPUserStatus &status,
|
||||||
int currentOnlineTill) {
|
Data::LastseenStatus currentStatus) {
|
||||||
return status.match([](const MTPDuserStatusEmpty &) {
|
return status.match([](const MTPDuserStatusEmpty &data) {
|
||||||
return kOnlineEmpty;
|
return Data::LastseenStatus::LongAgo();
|
||||||
}, [&](const MTPDuserStatusRecently&) {
|
}, [&](const MTPDuserStatusRecently &data) {
|
||||||
return IsRecentOnlineValue(currentOnlineTill)
|
return currentStatus.isLocalOnlineValue()
|
||||||
? currentOnlineTill
|
? Data::LastseenStatus::OnlineTill(
|
||||||
: kOnlineRecently;
|
currentStatus.onlineTill(),
|
||||||
}, [](const MTPDuserStatusLastWeek &) {
|
true,
|
||||||
return kOnlineLastWeek;
|
data.is_by_me())
|
||||||
}, [](const MTPDuserStatusLastMonth &) {
|
: Data::LastseenStatus::Recently(data.is_by_me());
|
||||||
return kOnlineLastMonth;
|
}, [](const MTPDuserStatusLastWeek &data) {
|
||||||
}, [](const MTPDuserStatusHidden &) {
|
return Data::LastseenStatus::WithinWeek(data.is_by_me());
|
||||||
return kOnlineHidden;
|
}, [](const MTPDuserStatusLastMonth &data) {
|
||||||
|
return Data::LastseenStatus::WithinMonth(data.is_by_me());
|
||||||
}, [](const MTPDuserStatusOnline& data) {
|
}, [](const MTPDuserStatusOnline& data) {
|
||||||
return data.vexpires().v;
|
return Data::LastseenStatus::OnlineTill(data.vexpires().v);
|
||||||
}, [](const MTPDuserStatusOffline &data) {
|
}, [](const MTPDuserStatusOffline &data) {
|
||||||
return data.vwas_online().v;
|
return Data::LastseenStatus::OnlineTill(data.vwas_online().v);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +77,19 @@ void UserData::setIsContact(bool is) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data::LastseenStatus UserData::lastseen() const {
|
||||||
|
return _lastseen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::updateLastseen(Data::LastseenStatus value) {
|
||||||
|
if (_lastseen == value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_lastseen = value;
|
||||||
|
owner().maybeStopWatchForOffline(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// see Serialize::readPeer as well
|
// see Serialize::readPeer as well
|
||||||
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
|
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
|
||||||
photo.match([&](const MTPDuserProfilePhoto &data) {
|
photo.match([&](const MTPDuserProfilePhoto &data) {
|
||||||
|
@ -305,11 +307,14 @@ void UserData::setNameOrPhone(const QString &newNameOrPhone) {
|
||||||
void UserData::madeAction(TimeId when) {
|
void UserData::madeAction(TimeId when) {
|
||||||
if (isBot() || isServiceUser() || when <= 0) {
|
if (isBot() || isServiceUser() || when <= 0) {
|
||||||
return;
|
return;
|
||||||
} else if (onlineTill <= 0 && -onlineTill < when) {
|
}
|
||||||
onlineTill = -when - kSetOnlineAfterActivity;
|
const auto till = lastseen().onlineTill();
|
||||||
session().changes().peerUpdated(this, UpdateFlag::OnlineStatus);
|
if (till < when + 1
|
||||||
} else if (onlineTill > 0 && onlineTill < when + 1) {
|
&& updateLastseen(
|
||||||
onlineTill = when + kSetOnlineAfterActivity;
|
Data::LastseenStatus::OnlineTill(
|
||||||
|
when + kSetOnlineAfterActivity,
|
||||||
|
!till || lastseen().isLocalOnlineValue(),
|
||||||
|
lastseen().isHiddenByMe()))) {
|
||||||
session().changes().peerUpdated(this, UpdateFlag::OnlineStatus);
|
session().changes().peerUpdated(this, UpdateFlag::OnlineStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_chat_participant_status.h"
|
#include "data/data_chat_participant_status.h"
|
||||||
|
#include "data/data_lastseen_status.h"
|
||||||
#include "data/data_user_names.h"
|
#include "data/data_user_names.h"
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ struct BotInfo {
|
||||||
ChatAdminRights channelAdminRights;
|
ChatAdminRights channelAdminRights;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UserDataFlag {
|
enum class UserDataFlag : uint32 {
|
||||||
Contact = (1 << 0),
|
Contact = (1 << 0),
|
||||||
MutualContact = (1 << 1),
|
MutualContact = (1 << 1),
|
||||||
Deleted = (1 << 2),
|
Deleted = (1 << 2),
|
||||||
|
@ -73,18 +74,9 @@ enum class UserDataFlag {
|
||||||
inline constexpr bool is_flag_type(UserDataFlag) { return true; };
|
inline constexpr bool is_flag_type(UserDataFlag) { return true; };
|
||||||
using UserDataFlags = base::flags<UserDataFlag>;
|
using UserDataFlags = base::flags<UserDataFlag>;
|
||||||
|
|
||||||
inline constexpr auto kOnlineEmpty = 0;
|
[[nodiscard]] Data::LastseenStatus LastseenFromMTP(
|
||||||
inline constexpr auto kOnlineRecently = -2;
|
const MTPUserStatus &status,
|
||||||
inline constexpr auto kOnlineLastWeek = -3;
|
Data::LastseenStatus currentStatus);
|
||||||
inline constexpr auto kOnlineLastMonth = -4;
|
|
||||||
inline constexpr auto kOnlineHidden = -5;
|
|
||||||
|
|
||||||
[[nodiscard]] int RecentOnlineAfter(TimeId when);
|
|
||||||
[[nodiscard]] bool IsRecentOnlineValue(int value);
|
|
||||||
[[nodiscard]] bool IsRecentOnline(int value, TimeId now);
|
|
||||||
[[nodiscard]] int OnlineTillFromMTP(
|
|
||||||
const MTPUserStatus& status,
|
|
||||||
int currentOnlineTill);
|
|
||||||
|
|
||||||
class UserData final : public PeerData {
|
class UserData final : public PeerData {
|
||||||
public:
|
public:
|
||||||
|
@ -160,7 +152,6 @@ public:
|
||||||
[[nodiscard]] QString editableUsername() const;
|
[[nodiscard]] QString editableUsername() const;
|
||||||
[[nodiscard]] const std::vector<QString> &usernames() const;
|
[[nodiscard]] const std::vector<QString> &usernames() const;
|
||||||
QString nameOrPhone;
|
QString nameOrPhone;
|
||||||
TimeId onlineTill = 0;
|
|
||||||
|
|
||||||
enum class ContactStatus : char {
|
enum class ContactStatus : char {
|
||||||
Unknown,
|
Unknown,
|
||||||
|
@ -171,6 +162,9 @@ public:
|
||||||
[[nodiscard]] bool isContact() const;
|
[[nodiscard]] bool isContact() const;
|
||||||
void setIsContact(bool is);
|
void setIsContact(bool is);
|
||||||
|
|
||||||
|
[[nodiscard]] Data::LastseenStatus lastseen() const;
|
||||||
|
bool updateLastseen(Data::LastseenStatus value);
|
||||||
|
|
||||||
enum class CallsStatus : char {
|
enum class CallsStatus : char {
|
||||||
Unknown,
|
Unknown,
|
||||||
Enabled,
|
Enabled,
|
||||||
|
@ -202,6 +196,7 @@ private:
|
||||||
-> const std::vector<Data::UnavailableReason> & override;
|
-> const std::vector<Data::UnavailableReason> & override;
|
||||||
|
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
|
Data::LastseenStatus _lastseen;
|
||||||
|
|
||||||
Data::UsernamesInfo _username;
|
Data::UsernamesInfo _username;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
|
||||||
if (!history) {
|
if (!history) {
|
||||||
return false;
|
return false;
|
||||||
} else if (const auto user = history->peer->asUser()) {
|
} else if (const auto user = history->peer->asUser()) {
|
||||||
return (user->onlineTill > 0);
|
return !user->lastseen().isHidden();
|
||||||
}
|
}
|
||||||
return !history->isForum();
|
return !history->isForum();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,10 +59,12 @@ TimeId DefaultScheduleTime() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanScheduleUntilOnline(not_null<PeerData*> peer) {
|
bool CanScheduleUntilOnline(not_null<PeerData*> peer) {
|
||||||
return !peer->isSelf()
|
if (const auto user = peer->asUser()) {
|
||||||
&& peer->isUser()
|
return !user->isSelf()
|
||||||
&& !peer->asUser()->isBot()
|
&& !user->isBot()
|
||||||
&& (peer->asUser()->onlineTill > 0);
|
&& !user->lastseen().isHidden();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleBox(
|
void ScheduleBox(
|
||||||
|
|
|
@ -1620,7 +1620,7 @@ void TopBarWidget::updateOnlineDisplay() {
|
||||||
auto online = 0;
|
auto online = 0;
|
||||||
auto onlyMe = true;
|
auto onlyMe = true;
|
||||||
for (const auto &user : chat->participants) {
|
for (const auto &user : chat->participants) {
|
||||||
if (user->onlineTill > now) {
|
if (user->lastseen().isOnline(now)) {
|
||||||
++online;
|
++online;
|
||||||
if (onlyMe && user != self) onlyMe = false;
|
if (onlyMe && user != self) onlyMe = false;
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1648,7 @@ void TopBarWidget::updateOnlineDisplay() {
|
||||||
auto online = 0;
|
auto online = 0;
|
||||||
auto onlyMe = true;
|
auto onlyMe = true;
|
||||||
for (auto &participant : std::as_const(channel->mgInfo->lastParticipants)) {
|
for (auto &participant : std::as_const(channel->mgInfo->lastParticipants)) {
|
||||||
if (participant->onlineTill > now) {
|
if (participant->lastseen().isOnline(now)) {
|
||||||
++online;
|
++online;
|
||||||
if (onlyMe && participant != self) {
|
if (onlyMe && participant != self) {
|
||||||
onlyMe = false;
|
onlyMe = false;
|
||||||
|
|
|
@ -326,7 +326,7 @@ Cover::Cover(
|
||||||
: nullptr)
|
: nullptr)
|
||||||
, _name(this, _st.name)
|
, _name(this, _st.name)
|
||||||
, _status(this, _st.status)
|
, _status(this, _st.status)
|
||||||
, _showLastSeen(this, tr::lng_status_lastseen_show(), _st.showLastSeen)
|
, _showLastSeen(this, tr::lng_status_lastseen_when(), _st.showLastSeen)
|
||||||
, _refreshStatusTimer([this] { refreshStatusText(); }) {
|
, _refreshStatusTimer([this] { refreshStatusText(); }) {
|
||||||
_peer->updateFull();
|
_peer->updateFull();
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ void Cover::setupShowLastSeen() {
|
||||||
&& !user->isServiceUser()
|
&& !user->isServiceUser()
|
||||||
&& user->session().premiumPossible()) {
|
&& user->session().premiumPossible()) {
|
||||||
if (user->session().premium()) {
|
if (user->session().premium()) {
|
||||||
if (user->onlineTill == kOnlineHidden) {
|
if (user->lastseen().isHiddenByMe()) {
|
||||||
user->updateFullForced();
|
user->updateFullForced();
|
||||||
}
|
}
|
||||||
_showLastSeen->hide();
|
_showLastSeen->hide();
|
||||||
|
@ -390,12 +390,12 @@ void Cover::setupShowLastSeen() {
|
||||||
Data::AmPremiumValue(&user->session())
|
Data::AmPremiumValue(&user->session())
|
||||||
) | rpl::start_with_next([=](auto, bool premium) {
|
) | rpl::start_with_next([=](auto, bool premium) {
|
||||||
const auto wasShown = !_showLastSeen->isHidden();
|
const auto wasShown = !_showLastSeen->isHidden();
|
||||||
const auto onlineHidden = (user->onlineTill == kOnlineHidden);
|
const auto hiddenByMe = user->lastseen().isHiddenByMe();
|
||||||
const auto shown = onlineHidden
|
const auto shown = hiddenByMe
|
||||||
&& !premium
|
&& !premium
|
||||||
&& user->session().premiumPossible();
|
&& user->session().premiumPossible();
|
||||||
_showLastSeen->setVisible(shown);
|
_showLastSeen->setVisible(shown);
|
||||||
if (wasShown && premium && onlineHidden) {
|
if (wasShown && premium && hiddenByMe) {
|
||||||
user->updateFullForced();
|
user->updateFullForced();
|
||||||
}
|
}
|
||||||
}, _showLastSeen->lifetime());
|
}, _showLastSeen->lifetime());
|
||||||
|
@ -405,7 +405,7 @@ void Cover::setupShowLastSeen() {
|
||||||
) | rpl::filter([=](Api::UserPrivacy::Rule rule) {
|
) | rpl::filter([=](Api::UserPrivacy::Rule rule) {
|
||||||
return (rule.option == Api::UserPrivacy::Option::Everyone);
|
return (rule.option == Api::UserPrivacy::Option::Everyone);
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
if (user->onlineTill == kOnlineHidden) {
|
if (user->lastseen().isHiddenByMe()) {
|
||||||
user->updateFullForced();
|
user->updateFullForced();
|
||||||
}
|
}
|
||||||
}, _showLastSeen->lifetime());
|
}, _showLastSeen->lifetime());
|
||||||
|
|
|
@ -90,10 +90,9 @@ userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true p
|
||||||
userStatusEmpty#9d05049 = UserStatus;
|
userStatusEmpty#9d05049 = UserStatus;
|
||||||
userStatusOnline#edb93949 expires:int = UserStatus;
|
userStatusOnline#edb93949 expires:int = UserStatus;
|
||||||
userStatusOffline#8c703f was_online:int = UserStatus;
|
userStatusOffline#8c703f was_online:int = UserStatus;
|
||||||
userStatusRecently#e26f42f1 = UserStatus;
|
userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus;
|
||||||
userStatusLastWeek#7bf09fc = UserStatus;
|
userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus;
|
||||||
userStatusLastMonth#77ebc742 = UserStatus;
|
userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus;
|
||||||
userStatusHidden#cf7d64b1 = UserStatus;
|
|
||||||
|
|
||||||
chatEmpty#29562865 id:long = Chat;
|
chatEmpty#29562865 id:long = Chat;
|
||||||
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||||
|
|
|
@ -134,22 +134,13 @@ NSRect PeerRectByIndex(int index) {
|
||||||
kCircleDiameter);
|
kCircleDiameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
[[nodiscard]] Data::LastseenStatus CalculateLastseenStatus(
|
||||||
if (peer->isSelf() || peer->isRepliesChat()) {
|
not_null<PeerData*> peer) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (const auto user = peer->asUser()) {
|
if (const auto user = peer->asUser()) {
|
||||||
if (!user->isServiceUser() && !user->isBot()) {
|
return user->lastseen();
|
||||||
const auto onlineTill = user->onlineTill;
|
|
||||||
return IsRecentOnlineValue(onlineTill)
|
|
||||||
? -onlineTill
|
|
||||||
: (onlineTill <= 0)
|
|
||||||
? 0
|
|
||||||
: onlineTill;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return Data::LastseenStatus();
|
||||||
};
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -175,7 +166,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
bool onTop = false;
|
bool onTop = false;
|
||||||
|
|
||||||
Ui::Animations::Simple onlineAnimation;
|
Ui::Animations::Simple onlineAnimation;
|
||||||
TimeId onlineTill = 0;
|
Data::LastseenStatus lastseen;
|
||||||
};
|
};
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
Main::Session *_session;
|
Main::Session *_session;
|
||||||
|
@ -570,10 +561,10 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
|
|
||||||
const auto callTimer = [=](const auto &pin) {
|
const auto callTimer = [=](const auto &pin) {
|
||||||
onlineTimer->cancel();
|
onlineTimer->cancel();
|
||||||
if (pin->onlineTill) {
|
if (const auto till = pin->lastseen.onlineTill()) {
|
||||||
const auto time = pin->onlineTill - base::unixtime::now();
|
const auto left = till - base::unixtime::now();
|
||||||
if (time > 0) {
|
if (left > 0) {
|
||||||
onlineTimer->callOnce(std::min(86400, time)
|
onlineTimer->callOnce(std::min(86400, left)
|
||||||
* crl::time(1000));
|
* crl::time(1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,7 +586,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &pin = *it;
|
const auto &pin = *it;
|
||||||
pin->onlineTill = CalculateOnlineTill(pin->peer);
|
pin->lastseen = CalculateLastseenStatus(pin->peer);
|
||||||
|
|
||||||
callTimer(pin);
|
callTimer(pin);
|
||||||
|
|
||||||
|
@ -603,9 +594,8 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
pin->onlineAnimation.stop();
|
pin->onlineAnimation.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto online = Data::OnlineTextActive(
|
const auto now = base::unixtime::now();
|
||||||
pin->onlineTill,
|
const auto online = pin->lastseen.isOnline(now);
|
||||||
base::unixtime::now());
|
|
||||||
if (pin->onlineAnimation.animating()) {
|
if (pin->onlineAnimation.animating()) {
|
||||||
pin->onlineAnimation.change(
|
pin->onlineAnimation.change(
|
||||||
online ? 1. : 0.,
|
online ? 1. : 0.,
|
||||||
|
@ -638,13 +628,12 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
const auto index = pair.second;
|
const auto index = pair.second;
|
||||||
auto peer = pair.first.history()->peer;
|
auto peer = pair.first.history()->peer;
|
||||||
auto view = peer->createUserpicView();
|
auto view = peer->createUserpicView();
|
||||||
const auto onlineTill = CalculateOnlineTill(peer);
|
return std::make_unique<Pin>(Pin{
|
||||||
Pin pin = {
|
|
||||||
.peer = std::move(peer),
|
.peer = std::move(peer),
|
||||||
.userpicView = std::move(view),
|
.userpicView = std::move(view),
|
||||||
.index = index,
|
.index = index,
|
||||||
.onlineTill = onlineTill };
|
.lastseen = CalculateLastseenStatus(peer),
|
||||||
return std::make_unique<Pin>(std::move(pin));
|
});
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
_selfUnpinned = ranges::none_of(peers, &PeerData::isSelf);
|
_selfUnpinned = ranges::none_of(peers, &PeerData::isSelf);
|
||||||
_repliesUnpinned = ranges::none_of(peers, &PeerData::isRepliesChat);
|
_repliesUnpinned = ranges::none_of(peers, &PeerData::isRepliesChat);
|
||||||
|
@ -837,9 +826,8 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
CGImageRelease(image);
|
CGImageRelease(image);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto online = Data::OnlineTextActive(
|
const auto now = base::unixtime::now();
|
||||||
pin->onlineTill,
|
const auto online = pin->lastseen.isOnline(now);
|
||||||
base::unixtime::now());
|
|
||||||
const auto value = pin->onlineAnimation.value(online ? 1. : 0.);
|
const auto value = pin->onlineAnimation.value(online ? 1. : 0.);
|
||||||
if (value < 0.05) {
|
if (value < 0.05) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -148,9 +148,8 @@ void GroupMembersWidget::refreshUserOnline(UserData *user) {
|
||||||
_now = base::unixtime::now();
|
_now = base::unixtime::now();
|
||||||
|
|
||||||
auto member = getMember(it->second);
|
auto member = getMember(it->second);
|
||||||
member->statusHasOnlineColor = !user->isBot()
|
member->lastseen = user->lastseen();
|
||||||
&& Data::OnlineTextActive(user->onlineTill, _now);
|
member->statusHasOnlineColor = Data::OnlineTextActive(user, _now);
|
||||||
member->onlineTill = user->onlineTill;
|
|
||||||
member->onlineForSort = user->isSelf()
|
member->onlineForSort = user->isSelf()
|
||||||
? std::numeric_limits<TimeId>::max()
|
? std::numeric_limits<TimeId>::max()
|
||||||
: Data::SortByOnlineValue(user, _now);
|
: Data::SortByOnlineValue(user, _now);
|
||||||
|
@ -184,10 +183,10 @@ void GroupMembersWidget::updateItemStatusText(Item *item) {
|
||||||
: tr::lng_status_bot_not_reads_all(tr::now);
|
: tr::lng_status_bot_not_reads_all(tr::now);
|
||||||
member->onlineTextTill = _now + 86400;
|
member->onlineTextTill = _now + 86400;
|
||||||
} else {
|
} else {
|
||||||
member->statusHasOnlineColor = Data::OnlineTextActive(member->onlineTill, _now);
|
member->statusHasOnlineColor = member->lastseen.isOnline(_now);
|
||||||
member->statusText = Data::OnlineText(member->onlineTill, _now);
|
member->statusText = Data::OnlineText(member->lastseen, _now);
|
||||||
const auto changeInMs = Data::OnlineChangeTimeout(
|
const auto changeInMs = Data::OnlineChangeTimeout(
|
||||||
member->onlineTill,
|
member->lastseen,
|
||||||
_now);
|
_now);
|
||||||
member->onlineTextTill = _now + TimeId(changeInMs / 1000);
|
member->onlineTextTill = _now + TimeId(changeInMs / 1000);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +246,8 @@ void GroupMembersWidget::updateOnlineCount() {
|
||||||
for (const auto item : items()) {
|
for (const auto item : items()) {
|
||||||
auto member = getMember(item);
|
auto member = getMember(item);
|
||||||
auto user = member->user();
|
auto user = member->user();
|
||||||
auto isOnline = !user->isBot() && Data::OnlineTextActive(member->onlineTill, _now);
|
auto isOnline = !user->isBot()
|
||||||
|
&& member->lastseen.isOnline(_now);
|
||||||
if (member->statusHasOnlineColor != isOnline) {
|
if (member->statusHasOnlineColor != isOnline) {
|
||||||
member->statusHasOnlineColor = isOnline;
|
member->statusHasOnlineColor = isOnline;
|
||||||
member->statusText = QString();
|
member->statusText = QString();
|
||||||
|
@ -439,9 +439,9 @@ auto GroupMembersWidget::computeMember(not_null<UserData*> user)
|
||||||
if (it == _membersByUser.cend()) {
|
if (it == _membersByUser.cend()) {
|
||||||
auto member = new Member(user);
|
auto member = new Member(user);
|
||||||
it = _membersByUser.emplace(user, member).first;
|
it = _membersByUser.emplace(user, member).first;
|
||||||
|
member->lastseen = user->lastseen();
|
||||||
member->statusHasOnlineColor = !user->isBot()
|
member->statusHasOnlineColor = !user->isBot()
|
||||||
&& Data::OnlineTextActive(user->onlineTill, _now);
|
&& member->lastseen.isOnline(_now);
|
||||||
member->onlineTill = user->onlineTill;
|
|
||||||
member->onlineForSort = Data::SortByOnlineValue(user, _now);
|
member->onlineForSort = Data::SortByOnlineValue(user, _now);
|
||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
|
@ -462,7 +462,7 @@ void GroupMembersWidget::updateOnlineDisplay() {
|
||||||
}
|
}
|
||||||
auto member = getMember(item);
|
auto member = getMember(item);
|
||||||
bool isOnline = !member->user()->isBot()
|
bool isOnline = !member->user()->isBot()
|
||||||
&& Data::OnlineTextActive(member->onlineTill, _now);
|
&& member->lastseen.isOnline(_now);
|
||||||
if (!isOnline) {
|
if (!isOnline) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
#include "data/data_lastseen_status.h"
|
||||||
#include "profile/profile_block_peer_list.h"
|
#include "profile/profile_block_peer_list.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -61,7 +62,7 @@ private:
|
||||||
not_null<UserData*> user() const;
|
not_null<UserData*> user() const;
|
||||||
|
|
||||||
TimeId onlineTextTill = 0;
|
TimeId onlineTextTill = 0;
|
||||||
TimeId onlineTill = 0;
|
Data::LastseenStatus lastseen;
|
||||||
TimeId onlineForSort = 0;
|
TimeId onlineForSort = 0;
|
||||||
};
|
};
|
||||||
Member *getMember(Item *item) {
|
Member *getMember(Item *item) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kModernImageLocationTag = std::numeric_limits<qint32>::min();
|
constexpr auto kModernImageLocationTag = std::numeric_limits<qint32>::min();
|
||||||
constexpr auto kVersionTag = uint64(0x77FF'FFFF'FFFF'FFFFULL);
|
constexpr auto kVersionTag = uint64(0x77FF'FFFF'FFFF'FFFFULL);
|
||||||
constexpr auto kVersion = 1;
|
constexpr auto kVersion = 2;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -111,12 +111,12 @@ std::optional<ImageLocation> readImageLocation(
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 peerSize(not_null<PeerData*> peer) {
|
uint32 peerSize(not_null<PeerData*> peer) {
|
||||||
uint32 result = sizeof(quint64)
|
uint32 result = sizeof(quint64) // id
|
||||||
+ sizeof(quint64)
|
+ sizeof(quint64) // version tag
|
||||||
+ sizeof(qint32)
|
+ sizeof(qint32) // version
|
||||||
+ sizeof(quint64)
|
+ sizeof(quint64) // userpic photo id
|
||||||
+ imageLocationSize(peer->userpicLocation())
|
+ imageLocationSize(peer->userpicLocation())
|
||||||
+ sizeof(qint32);
|
+ sizeof(qint32); // userpic has video
|
||||||
if (const auto user = peer->asUser()) {
|
if (const auto user = peer->asUser()) {
|
||||||
result += stringSize(user->firstName)
|
result += stringSize(user->firstName)
|
||||||
+ stringSize(user->lastName)
|
+ stringSize(user->lastName)
|
||||||
|
@ -124,7 +124,7 @@ uint32 peerSize(not_null<PeerData*> peer) {
|
||||||
+ stringSize(user->username())
|
+ stringSize(user->username())
|
||||||
+ sizeof(quint64) // access
|
+ sizeof(quint64) // access
|
||||||
+ sizeof(qint32) // flags
|
+ sizeof(qint32) // flags
|
||||||
+ sizeof(qint32) // onlineTill
|
+ sizeof(quint32) // lastseen
|
||||||
+ sizeof(qint32) // contact
|
+ sizeof(qint32) // contact
|
||||||
+ sizeof(qint32); // botInfoVersion
|
+ sizeof(qint32); // botInfoVersion
|
||||||
} else if (const auto chat = peer->asChat()) {
|
} else if (const auto chat = peer->asChat()) {
|
||||||
|
@ -168,7 +168,7 @@ void writePeer(QDataStream &stream, not_null<PeerData*> peer) {
|
||||||
<< quint64(user->accessHash())
|
<< quint64(user->accessHash())
|
||||||
<< qint32(user->flags())
|
<< qint32(user->flags())
|
||||||
<< botInlinePlaceholder
|
<< botInlinePlaceholder
|
||||||
<< qint32(user->onlineTill)
|
<< quint32(user->lastseen().serialize())
|
||||||
<< qint32(user->isContact() ? 1 : 0)
|
<< qint32(user->isContact() ? 1 : 0)
|
||||||
<< qint32(user->isBot() ? user->botInfo->version : -1);
|
<< qint32(user->isBot() ? user->botInfo->version : -1);
|
||||||
} else if (const auto chat = peer->asChat()) {
|
} else if (const auto chat = peer->asChat()) {
|
||||||
|
@ -233,7 +233,8 @@ PeerData *readPeer(
|
||||||
if (const auto user = result->asUser()) {
|
if (const auto user = result->asUser()) {
|
||||||
QString first, last, phone, username, inlinePlaceholder;
|
QString first, last, phone, username, inlinePlaceholder;
|
||||||
quint64 access;
|
quint64 access;
|
||||||
qint32 flags = 0, onlineTill, contact, botInfoVersion;
|
qint32 flags = 0, contact, botInfoVersion;
|
||||||
|
quint32 lastseen;
|
||||||
stream >> first >> last >> phone >> username >> access;
|
stream >> first >> last >> phone >> username >> access;
|
||||||
if (streamAppVersion >= 9012) {
|
if (streamAppVersion >= 9012) {
|
||||||
stream >> flags;
|
stream >> flags;
|
||||||
|
@ -241,7 +242,7 @@ PeerData *readPeer(
|
||||||
if (streamAppVersion >= 9016) {
|
if (streamAppVersion >= 9016) {
|
||||||
stream >> inlinePlaceholder;
|
stream >> inlinePlaceholder;
|
||||||
}
|
}
|
||||||
stream >> onlineTill >> contact >> botInfoVersion;
|
stream >> lastseen >> contact >> botInfoVersion;
|
||||||
|
|
||||||
userpicAccessHash = access;
|
userpicAccessHash = access;
|
||||||
|
|
||||||
|
@ -285,7 +286,9 @@ PeerData *readPeer(
|
||||||
user->setFlags((user->flags() & ~flagsMask) | flagsSet);
|
user->setFlags((user->flags() & ~flagsMask) | flagsSet);
|
||||||
}
|
}
|
||||||
user->setAccessHash(access);
|
user->setAccessHash(access);
|
||||||
user->onlineTill = onlineTill;
|
user->updateLastseen((version > 1)
|
||||||
|
? Data::LastseenStatus::FromSerialized(lastseen)
|
||||||
|
: Data::LastseenStatus::FromLegacy(lastseen));
|
||||||
user->setIsContact(contact == 1);
|
user->setIsContact(contact == 1);
|
||||||
user->setBotInfoVersion(botInfoVersion);
|
user->setBotInfoVersion(botInfoVersion);
|
||||||
if (!inlinePlaceholder.isEmpty() && user->isBot()) {
|
if (!inlinePlaceholder.isEmpty() && user->isBot()) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue