1
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-04-01 00:08:02 +00:00

Track dialog row offline status by timer.

Fixes .
This commit is contained in:
John Preston 2022-10-24 11:22:26 +04:00
parent 0cba9e4a22
commit ed895ace66
10 changed files with 104 additions and 26 deletions

View File

@ -945,6 +945,7 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
Data::PeerUpdate::Flag::OnlineStatus); Data::PeerUpdate::Flag::OnlineStatus);
if (!isOnline) { // Went offline, so we need to save message draft to the cloud. if (!isOnline) { // Went offline, so we need to save message draft to the cloud.
api().saveCurrentDraftToCloud(); api().saveCurrentDraftToCloud();
session().data().maybeStopWatchForOffline(self);
} }
_lastSetOnline = ms; _lastSetOnline = ms;
@ -1856,6 +1857,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
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()) {
if (d.vstatus().type() == mtpc_userStatusOffline if (d.vstatus().type() == mtpc_userStatusOffline

View File

@ -1843,6 +1843,7 @@ void ApiWrap::updatePrivacyLastSeens() {
session().changes().peerUpdated( session().changes().peerUpdated(
user, user,
Data::PeerUpdate::Flag::OnlineStatus); Data::PeerUpdate::Flag::OnlineStatus);
session().data().maybeStopWatchForOffline(user);
}); });
if (_contactsStatusesRequestId) { if (_contactsStatusesRequestId) {
@ -1856,12 +1857,15 @@ void ApiWrap::updatePrivacyLastSeens() {
auto &data = item.c_contactStatus(); auto &data = item.c_contactStatus();
if (auto user = _session->data().userLoaded(data.vuser_id())) { if (auto user = _session->data().userLoaded(data.vuser_id())) {
auto oldOnlineTill = user->onlineTill; auto oldOnlineTill = user->onlineTill;
auto newOnlineTill = OnlineTillFromStatus(data.vstatus(), oldOnlineTill); auto newOnlineTill = OnlineTillFromStatus(
data.vstatus(),
oldOnlineTill);
if (oldOnlineTill != newOnlineTill) { if (oldOnlineTill != newOnlineTill) {
user->onlineTill = newOnlineTill; user->onlineTill = newOnlineTill;
session().changes().peerUpdated( session().changes().peerUpdated(
user, user,
Data::PeerUpdate::Flag::OnlineStatus); Data::PeerUpdate::Flag::OnlineStatus);
session().data().maybeStopWatchForOffline(user);
} }
} }
} }

View File

@ -460,8 +460,11 @@ bool OnlineTextActive(not_null<UserData*> user, TimeId now) {
return OnlineTextActive(user->onlineTill, now); return OnlineTextActive(user->onlineTill, now);
} }
bool IsUserOnline(not_null<UserData*> user) { bool IsUserOnline(not_null<UserData*> user, TimeId now) {
return OnlineTextActive(user, base::unixtime::now()); if (!now) {
now = base::unixtime::now();
}
return OnlineTextActive(user, now);
} }
bool ChannelHasActiveCall(not_null<ChannelData*> channel) { bool ChannelHasActiveCall(not_null<ChannelData*> channel) {

View File

@ -122,7 +122,7 @@ inline auto PeerFullFlagValue(
[[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(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); [[nodiscard]] bool IsUserOnline(not_null<UserData*> user, TimeId now = 0);
[[nodiscard]] bool ChannelHasActiveCall(not_null<ChannelData*> channel); [[nodiscard]] bool ChannelHasActiveCall(not_null<ChannelData*> channel);
[[nodiscard]] rpl::producer<QImage> PeerUserpicImageValue( [[nodiscard]] rpl::producer<QImage> PeerUserpicImageValue(

View File

@ -246,6 +246,7 @@ Session::Session(not_null<Main::Session*> session)
, _ttlCheckTimer([=] { checkTTLs(); }) , _ttlCheckTimer([=] { checkTTLs(); })
, _selfDestructTimer([=] { checkSelfDestructItems(); }) , _selfDestructTimer([=] { checkSelfDestructItems(); })
, _pollsClosingTimer([=] { checkPollsClosings(); }) , _pollsClosingTimer([=] { checkPollsClosings(); })
, _watchForOfflineTimer([=] { checkLocalUsersWentOffline(); })
, _groups(this) , _groups(this)
, _chatsFilters(std::make_unique<ChatFilters>(this)) , _chatsFilters(std::make_unique<ChatFilters>(this))
, _scheduledMessages(std::make_unique<ScheduledMessages>(this)) , _scheduledMessages(std::make_unique<ScheduledMessages>(this))
@ -644,6 +645,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
if (oldOnlineTill != newOnlineTill) { if (oldOnlineTill != newOnlineTill) {
result->onlineTill = newOnlineTill; result->onlineTill = newOnlineTill;
flags |= UpdateFlag::OnlineStatus; flags |= UpdateFlag::OnlineStatus;
session().data().maybeStopWatchForOffline(result);
} }
} }
@ -968,6 +970,64 @@ GroupCall *Session::groupCall(CallId callId) const {
return (i != end(_groupCalls)) ? i->second.get() : nullptr; return (i != end(_groupCalls)) ? i->second.get() : nullptr;
} }
void Session::watchForOffline(not_null<UserData*> user, TimeId now) {
if (!now) {
now = base::unixtime::now();
}
if (!Data::IsUserOnline(user, now)) {
return;
}
const auto till = user->onlineTill;
const auto [i, ok] = _watchingForOffline.emplace(user, till);
if (!ok) {
if (i->second == till) {
return;
}
i->second = till;
}
const auto timeout = Data::OnlineChangeTimeout(till, now);
const auto fires = _watchForOfflineTimer.isActive()
? _watchForOfflineTimer.remainingTime()
: -1;
if (fires >= 0 && fires <= timeout) {
return;
}
_watchForOfflineTimer.callOnce(std::max(timeout, crl::time(1)));
}
void Session::maybeStopWatchForOffline(not_null<UserData*> user) {
if (Data::IsUserOnline(user)) {
return;
} else if (_watchingForOffline.remove(user)
&& _watchingForOffline.empty()) {
_watchForOfflineTimer.cancel();
}
}
void Session::checkLocalUsersWentOffline() {
_watchForOfflineTimer.cancel();
auto minimal = 86400 * crl::time(1000);
const auto now = base::unixtime::now();
for (auto i = begin(_watchingForOffline)
; i != end(_watchingForOffline);) {
const auto user = i->first;
if (!Data::IsUserOnline(user, now)) {
i = _watchingForOffline.erase(i);
session().changes().peerUpdated(
user,
PeerUpdate::Flag::OnlineStatus);
} else {
const auto timeout = Data::OnlineChangeTimeout(user, now);
accumulate_min(minimal, timeout);
++i;
}
}
if (!_watchingForOffline.empty()) {
_watchForOfflineTimer.callOnce(std::max(minimal, crl::time(1)));
}
}
auto Session::invitedToCallUsers(CallId callId) const auto Session::invitedToCallUsers(CallId callId) const
-> const base::flat_set<not_null<UserData*>> & { -> const base::flat_set<not_null<UserData*>> & {
static const base::flat_set<not_null<UserData*>> kEmpty; static const base::flat_set<not_null<UserData*>> kEmpty;

View File

@ -192,6 +192,9 @@ public:
void unregisterGroupCall(not_null<GroupCall*> call); void unregisterGroupCall(not_null<GroupCall*> call);
GroupCall *groupCall(CallId callId) const; GroupCall *groupCall(CallId callId) const;
void watchForOffline(not_null<UserData*> user, TimeId now = 0);
void maybeStopWatchForOffline(not_null<UserData*> user);
[[nodiscard]] auto invitedToCallUsers(CallId callId) const [[nodiscard]] auto invitedToCallUsers(CallId callId) const
-> const base::flat_set<not_null<UserData*>> &; -> const base::flat_set<not_null<UserData*>> &;
void registerInvitedToCallUser( void registerInvitedToCallUser(
@ -717,6 +720,7 @@ private:
void setupUserIsContactViewer(); void setupUserIsContactViewer();
void checkSelfDestructItems(); void checkSelfDestructItems();
void checkLocalUsersWentOffline();
void scheduleNextTTLs(); void scheduleNextTTLs();
void checkTTLs(); void checkTTLs();
@ -976,6 +980,9 @@ private:
std::vector<WallPaper> _wallpapers; std::vector<WallPaper> _wallpapers;
uint64 _wallpapersHash = 0; uint64 _wallpapersHash = 0;
base::flat_map<not_null<UserData*>, TimeId> _watchingForOffline;
base::Timer _watchForOfflineTimer;
rpl::event_stream<WebViewResultSent> _webViewResultSent; rpl::event_stream<WebViewResultSent> _webViewResultSent;
Groups _groups; Groups _groups;

View File

@ -193,7 +193,7 @@ InnerWidget::InnerWidget(
session().data().sendActionManager().speakingAnimationUpdated( session().data().sendActionManager().speakingAnimationUpdated(
) | rpl::start_with_next([=](not_null<History*> history) { ) | rpl::start_with_next([=](not_null<History*> history) {
updateDialogRowCornerStatus(history); repaintDialogRowCornerStatus(history);
}, lifetime()); }, lifetime());
setupOnlineStatusCheck(); setupOnlineStatusCheck();
@ -3181,15 +3181,15 @@ void InnerWidget::setupOnlineStatusCheck() {
Data::PeerUpdate::Flag::OnlineStatus Data::PeerUpdate::Flag::OnlineStatus
| Data::PeerUpdate::Flag::GroupCall | Data::PeerUpdate::Flag::GroupCall
) | rpl::start_with_next([=](const Data::PeerUpdate &update) { ) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
if (update.peer->isUser()) { if (const auto user = update.peer->asUser()) {
userOnlineUpdated(update.peer); userOnlineUpdated(user);
} else { } else {
groupHasCallUpdated(update.peer); groupHasCallUpdated(update.peer);
} }
}, lifetime()); }, lifetime());
} }
void InnerWidget::updateDialogRowCornerStatus(not_null<History*> history) { void InnerWidget::repaintDialogRowCornerStatus(not_null<History*> history) {
const auto user = history->peer->isUser(); const auto user = history->peer->isUser();
const auto size = user const auto size = user
? st::dialogsOnlineBadgeSize ? st::dialogsOnlineBadgeSize
@ -3217,16 +3217,15 @@ void InnerWidget::updateDialogRowCornerStatus(not_null<History*> history) {
UpdateRowSection::Default | UpdateRowSection::Filtered); UpdateRowSection::Default | UpdateRowSection::Filtered);
} }
void InnerWidget::userOnlineUpdated(not_null<PeerData*> peer) { void InnerWidget::userOnlineUpdated(not_null<UserData*> user) {
const auto user = peer->isSelf() ? nullptr : peer->asUser(); if (!user->isSelf()) {
if (!user) {
return; return;
} }
const auto history = session().data().historyLoaded(user); const auto history = session().data().historyLoaded(user);
if (!history) { if (!history) {
return; return;
} }
updateRowCornerStatusShown(history, Data::IsUserOnline(user)); updateRowCornerStatusShown(history);
} }
void InnerWidget::groupHasCallUpdated(not_null<PeerData*> peer) { void InnerWidget::groupHasCallUpdated(not_null<PeerData*> peer) {
@ -3238,14 +3237,12 @@ void InnerWidget::groupHasCallUpdated(not_null<PeerData*> peer) {
if (!history) { if (!history) {
return; return;
} }
updateRowCornerStatusShown(history, Data::ChannelHasActiveCall(group)); updateRowCornerStatusShown(history);
} }
void InnerWidget::updateRowCornerStatusShown( void InnerWidget::updateRowCornerStatusShown(not_null<History*> history) {
not_null<History*> history,
bool shown) {
const auto repaint = [=] { const auto repaint = [=] {
updateDialogRowCornerStatus(history); repaintDialogRowCornerStatus(history);
}; };
repaint(); repaint();

View File

@ -248,13 +248,11 @@ private:
int defaultRowTop(not_null<Row*> row) const; int defaultRowTop(not_null<Row*> row) const;
void setupOnlineStatusCheck(); void setupOnlineStatusCheck();
void userOnlineUpdated(not_null<PeerData*> peer); void userOnlineUpdated(not_null<UserData*> user);
void groupHasCallUpdated(not_null<PeerData*> peer); void groupHasCallUpdated(not_null<PeerData*> peer);
void updateRowCornerStatusShown( void updateRowCornerStatusShown(not_null<History*> history);
not_null<History*> history, void repaintDialogRowCornerStatus(not_null<History*> history);
bool shown);
void updateDialogRowCornerStatus(not_null<History*> history);
void setupShortcuts(); void setupShortcuts();
RowDescriptor computeJump( RowDescriptor computeJump(

View File

@ -15,10 +15,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/ui/dialogs_video_userpic.h" #include "dialogs/ui/dialogs_video_userpic.h"
#include "dialogs/ui/dialogs_layout.h" #include "dialogs/ui/dialogs_layout.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_session.h"
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "base/unixtime.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
@ -196,15 +198,20 @@ void Row::setCornerBadgeShown(
void Row::updateCornerBadgeShown( void Row::updateCornerBadgeShown(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Fn<void()> updateCallback) const { Fn<void()> updateCallback) const {
const auto user = peer->asUser();
const auto now = user ? base::unixtime::now() : TimeId();
const auto shown = [&] { const auto shown = [&] {
if (const auto user = peer->asUser()) { if (user) {
return Data::IsUserOnline(user); return Data::IsUserOnline(user, now);
} else if (const auto channel = peer->asChannel()) { } else if (const auto channel = peer->asChannel()) {
return Data::ChannelHasActiveCall(channel); return Data::ChannelHasActiveCall(channel);
} }
return false; return false;
}(); }();
setCornerBadgeShown(shown, std::move(updateCallback)); setCornerBadgeShown(shown, std::move(updateCallback));
if (shown && user) {
peer->owner().watchForOffline(user, now);
}
} }
void Row::ensureCornerBadgeUserpic() const { void Row::ensureCornerBadgeUserpic() const {

View File

@ -1338,9 +1338,9 @@ void TopBarWidget::updateOnlineDisplayTimer() {
} }
const auto now = base::unixtime::now(); const auto now = base::unixtime::now();
auto minTimeout = crl::time(86400); auto minTimeout = 86400 * crl::time(1000);
const auto handleUser = [&](not_null<UserData*> user) { const auto handleUser = [&](not_null<UserData*> user) {
auto hisTimeout = Data::OnlineChangeTimeout(user, now); const auto hisTimeout = Data::OnlineChangeTimeout(user, now);
accumulate_min(minTimeout, hisTimeout); accumulate_min(minTimeout, hisTimeout);
}; };
if (const auto user = peer->asUser()) { if (const auto user = peer->asUser()) {