Merge v4.14.13

# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp
#	Telegram/SourceFiles/history/view/media/history_view_photo.cpp
#	Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
#	Telegram/SourceFiles/mainwidget.cpp
#	Telegram/lib_ui
This commit is contained in:
ZavaruKitsu
2024-02-03 23:20:50 +03:00
251 changed files with 6957 additions and 2361 deletions
@@ -84,18 +84,61 @@ void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
u"AUTOARCHIVE_POPULAR"_q);
}
void GlobalPrivacy::updateHideReadTime(bool hide) {
update(
archiveAndMuteCurrent(),
unarchiveOnNewMessageCurrent(),
hide,
newRequirePremiumCurrent());
}
bool GlobalPrivacy::hideReadTimeCurrent() const {
return _hideReadTime.current();
}
rpl::producer<bool> GlobalPrivacy::hideReadTime() const {
return _hideReadTime.value();
}
void GlobalPrivacy::updateNewRequirePremium(bool value) {
update(
archiveAndMuteCurrent(),
unarchiveOnNewMessageCurrent(),
hideReadTimeCurrent(),
value);
}
bool GlobalPrivacy::newRequirePremiumCurrent() const {
return _newRequirePremium.current();
}
rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
return _newRequirePremium.value();
}
void GlobalPrivacy::updateArchiveAndMute(bool value) {
update(value, unarchiveOnNewMessageCurrent());
update(
value,
unarchiveOnNewMessageCurrent(),
hideReadTimeCurrent(),
newRequirePremiumCurrent());
}
void GlobalPrivacy::updateUnarchiveOnNewMessage(
UnarchiveOnNewMessage value) {
update(archiveAndMuteCurrent(), value);
update(
archiveAndMuteCurrent(),
value,
hideReadTimeCurrent(),
newRequirePremiumCurrent());
}
void GlobalPrivacy::update(
bool archiveAndMute,
UnarchiveOnNewMessage unarchiveOnNewMessage) {
UnarchiveOnNewMessage unarchiveOnNewMessage,
bool hideReadTime,
bool newRequirePremium) {
using Flag = MTPDglobalPrivacySettings::Flag;
_api.request(_requestId).cancel();
@@ -108,17 +151,26 @@ void GlobalPrivacy::update(
: Flag())
| (unarchiveOnNewMessage != UnarchiveOnNewMessage::AnyUnmuted
? Flag::f_keep_archived_folders
: Flag())
| (hideReadTime ? Flag::f_hide_read_marks : Flag())
| ((newRequirePremium && _session->premium())
? Flag::f_new_noncontact_peers_require_premium
: Flag());
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
MTP_globalPrivacySettings(MTP_flags(flags))
)).done([=](const MTPGlobalPrivacySettings &result) {
_requestId = 0;
apply(result);
}).fail([=] {
}).fail([=](const MTP::Error &error) {
_requestId = 0;
if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
update(archiveAndMute, unarchiveOnNewMessage, hideReadTime, {});
}
}).send();
_archiveAndMute = archiveAndMute;
_unarchiveOnNewMessage = unarchiveOnNewMessage;
_hideReadTime = hideReadTime;
_newRequirePremium = newRequirePremium;
}
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
@@ -129,6 +181,8 @@ void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
: data.is_keep_archived_folders()
? UnarchiveOnNewMessage::NotInFoldersUnmuted
: UnarchiveOnNewMessage::AnyUnmuted;
_hideReadTime = data.is_hide_read_marks();
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
});
}
+13 -1
View File
@@ -41,12 +41,22 @@ public:
[[nodiscard]] rpl::producer<> suggestArchiveAndMute() const;
void dismissArchiveAndMuteSuggestion();
void updateHideReadTime(bool hide);
[[nodiscard]] bool hideReadTimeCurrent() const;
[[nodiscard]] rpl::producer<bool> hideReadTime() const;
void updateNewRequirePremium(bool value);
[[nodiscard]] bool newRequirePremiumCurrent() const;
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
private:
void apply(const MTPGlobalPrivacySettings &data);
void update(
bool archiveAndMute,
UnarchiveOnNewMessage unarchiveOnNewMessage);
UnarchiveOnNewMessage unarchiveOnNewMessage,
bool hideReadTime,
bool newRequirePremium);
const not_null<Main::Session*> _session;
MTP::Sender _api;
@@ -55,6 +65,8 @@ private:
rpl::variable<UnarchiveOnNewMessage> _unarchiveOnNewMessage
= UnarchiveOnNewMessage::None;
rpl::variable<bool> _showArchiveAndMute = false;
rpl::variable<bool> _hideReadTime = false;
rpl::variable<bool> _newRequirePremium = false;
std::vector<Fn<void()>> _callbacks;
};
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "data/data_channel.h"
#include "data/data_histories.h"
#include "data/data_message_reaction_id.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "history/history.h"
@@ -43,6 +44,23 @@ constexpr auto kSearchPerPage = 50;
return result;
}
[[nodiscard]] QString RequestToToken(
const MessagesSearch::Request &request) {
auto result = request.query;
if (request.from) {
result += '\n' + QString::number(request.from->id.value);
}
for (const auto &tag : request.tags) {
result += '\n';
if (const auto customId = tag.custom()) {
result += u"custom"_q + QString::number(customId);
} else {
result += u"emoji"_q + tag.emoji();
}
}
return result;
}
} // namespace
MessagesSearch::MessagesSearch(not_null<History*> history)
@@ -54,9 +72,8 @@ MessagesSearch::~MessagesSearch() {
base::take(_searchInHistoryRequest));
}
void MessagesSearch::searchMessages(const QString &query, PeerData *from) {
_query = query;
_from = from;
void MessagesSearch::searchMessages(Request request) {
_request = std::move(request);
_offsetId = {};
searchRequest();
}
@@ -69,8 +86,7 @@ void MessagesSearch::searchMore() {
}
void MessagesSearch::searchRequest() {
const auto nextToken = _query
+ QString::number(_from ? _from->id.value : 0);
const auto nextToken = RequestToToken(_request);
if (!_offsetId) {
const auto it = _cacheOfStartByToken.find(nextToken);
if (it != end(_cacheOfStartByToken)) {
@@ -80,18 +96,21 @@ void MessagesSearch::searchRequest() {
}
}
auto callback = [=](Fn<void()> finish) {
const auto flags = _from
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
: MTP_flags(0);
using Flag = MTPmessages_Search::Flag;
const auto from = _request.from;
const auto fromPeer = _history->peer->isUser() ? nullptr : from;
const auto savedPeer = _history->peer->isSelf() ? from : nullptr;
_requestId = _history->session().api().request(MTPmessages_Search(
flags,
MTP_flags((fromPeer ? Flag::f_from_id : Flag())
| (savedPeer ? Flag::f_saved_peer_id : Flag())
| (_request.tags.empty() ? Flag() : Flag::f_saved_reaction)),
_history->peer->input,
MTP_string(_query),
(_from
? _from->input
: MTP_inputPeerEmpty()),
MTPInputPeer(), // saved_peer_id
MTPVector<MTPReaction>(), // saved_reaction
MTP_string(_request.query),
(fromPeer ? fromPeer->input : MTP_inputPeerEmpty()),
(savedPeer ? savedPeer->input : MTP_inputPeerEmpty()),
MTP_vector_from_range(_request.tags | ranges::views::transform(
Data::ReactionToMTP
)),
MTPint(), // top_msg_id
MTP_inputMessagesFilterEmpty(),
MTP_int(0), // min_date
+22 -3
View File
@@ -7,10 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/qt/qt_compare.h"
#include "data/data_message_reaction_id.h"
class HistoryItem;
class History;
class PeerData;
namespace Data {
struct ReactionId;
} // namespace Data
namespace Api {
struct FoundMessages {
@@ -21,10 +28,23 @@ struct FoundMessages {
class MessagesSearch final {
public:
struct Request {
QString query;
PeerData *from = nullptr;
std::vector<Data::ReactionId> tags;
friend inline bool operator==(
const Request &,
const Request &) = default;
friend inline auto operator<=>(
const Request &,
const Request &) = default;
};
explicit MessagesSearch(not_null<History*> history);
~MessagesSearch();
void searchMessages(const QString &query, PeerData *from);
void searchMessages(Request request);
void searchMore();
[[nodiscard]] rpl::producer<FoundMessages> messagesFounds() const;
@@ -41,8 +61,7 @@ private:
base::flat_map<QString, TLMessages> _cacheOfStartByToken;
QString _query;
PeerData *_from = nullptr;
Request _request;
MsgId _offsetId;
int _searchInHistoryRequest = 0; // Not real mtpRequestId.
@@ -11,12 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Api {
bool MessagesSearchMerged::RequestCompare::operator()(
const Request &a,
const Request &b) const {
return (a.query < b.query) && (a.from < b.from);
}
MessagesSearchMerged::MessagesSearchMerged(not_null<History*> history)
: _apiSearch(history) {
if (const auto migrated = history->migrateFrom()) {
@@ -88,9 +82,9 @@ void MessagesSearchMerged::clear() {
void MessagesSearchMerged::search(const Request &search) {
if (_migratedSearch) {
_waitingForTotal = true;
_migratedSearch->searchMessages(search.query, search.from);
_migratedSearch->searchMessages(search);
}
_apiSearch.searchMessages(search.query, search.from);
_apiSearch.searchMessages(search);
}
void MessagesSearchMerged::searchMore() {
@@ -12,19 +12,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
class PeerData;
namespace Data {
struct ReactionId;
} // namespace Data
namespace Api {
// Search in both of history and migrated history, if it exists.
class MessagesSearchMerged final {
public:
struct Request {
QString query;
PeerData *from = nullptr;
};
struct RequestCompare {
bool operator()(const Request &a, const Request &b) const;
};
using CachedRequests = std::set<Request, RequestCompare>;
using Request = MessagesSearch::Request;
using CachedRequests = base::flat_set<Request>;
MessagesSearchMerged(not_null<History*> history);
+115
View File
@@ -15,6 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer.h"
#include "data/data_peer_values.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/view/history_view_element.h"
#include "history/history.h"
#include "history/history_item.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
@@ -334,6 +338,72 @@ const Data::SubscriptionOptions &Premium::subscriptionOptions() const {
return _subscriptionOptions;
}
rpl::producer<> Premium::somePremiumRequiredResolved() const {
return _somePremiumRequiredResolved.events();
}
void Premium::resolvePremiumRequired(not_null<UserData*> user) {
_resolvePremiumRequiredUsers.emplace(user);
if (!_premiumRequiredRequestScheduled
&& _resolvePremiumRequestedUsers.empty()) {
_premiumRequiredRequestScheduled = true;
crl::on_main(_session, [=] {
requestPremiumRequiredSlice();
});
}
}
void Premium::requestPremiumRequiredSlice() {
_premiumRequiredRequestScheduled = false;
if (!_resolvePremiumRequestedUsers.empty()
|| _resolvePremiumRequiredUsers.empty()) {
return;
}
constexpr auto kPerRequest = 100;
auto users = MTP_vector_from_range(_resolvePremiumRequiredUsers
| ranges::views::transform(&UserData::inputUser));
if (users.v.size() > kPerRequest) {
auto shortened = users.v;
shortened.resize(kPerRequest);
users = MTP_vector<MTPInputUser>(std::move(shortened));
const auto from = begin(_resolvePremiumRequiredUsers);
_resolvePremiumRequestedUsers = { from, from + kPerRequest };
_resolvePremiumRequiredUsers.erase(from, from + kPerRequest);
} else {
_resolvePremiumRequestedUsers
= base::take(_resolvePremiumRequiredUsers);
}
const auto finish = [=](const QVector<MTPBool> &list) {
constexpr auto me = UserDataFlag::MeRequiresPremiumToWrite;
constexpr auto known = UserDataFlag::RequirePremiumToWriteKnown;
constexpr auto mask = me | known;
auto index = 0;
for (const auto &user : base::take(_resolvePremiumRequestedUsers)) {
const auto require = (index < list.size())
&& mtpIsTrue(list[index++]);
user->setFlags((user->flags() & ~mask)
| known
| (require ? me : UserDataFlag()));
}
if (!_premiumRequiredRequestScheduled
&& !_resolvePremiumRequiredUsers.empty()) {
_premiumRequiredRequestScheduled = true;
crl::on_main(_session, [=] {
requestPremiumRequiredSlice();
});
}
_somePremiumRequiredResolved.fire({});
};
_session->api().request(
MTPusers_GetIsPremiumRequiredToContact(std::move(users))
).done([=](const MTPVector<MTPBool> &result) {
finish(result.v);
}).fail([=] {
finish({});
}).send();
}
PremiumGiftCodeOptions::PremiumGiftCodeOptions(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
@@ -494,4 +564,49 @@ bool PremiumGiftCodeOptions::giveawayGiftsPurchaseAvailable() const {
false);
}
RequirePremiumState ResolveRequiresPremiumToWrite(
not_null<PeerData*> peer,
History *maybeHistory) {
const auto user = peer->asUser();
if (!user
|| !user->someRequirePremiumToWrite()
|| user->session().premium()) {
return RequirePremiumState::No;
} else if (user->requirePremiumToWriteKnown()) {
return user->meRequiresPremiumToWrite()
? RequirePremiumState::Yes
: RequirePremiumState::No;
} else if (user->flags() & UserDataFlag::MutualContact) {
return RequirePremiumState::No;
} else if (!maybeHistory) {
return RequirePremiumState::Unknown;
}
const auto update = [&](bool require) {
using Flag = UserDataFlag;
constexpr auto known = Flag::RequirePremiumToWriteKnown;
constexpr auto me = Flag::MeRequiresPremiumToWrite;
user->setFlags((user->flags() & ~me)
| known
| (require ? me : Flag()));
};
// We allow this potentially-heavy loop because in case we've opened
// the chat and have a lot of messages `requires_premium` will be known.
for (const auto &block : maybeHistory->blocks) {
for (const auto &view : block->messages) {
const auto item = view->data();
if (!item->out() && !item->isService()) {
update(false);
return RequirePremiumState::No;
}
}
}
if (user->isContact() // Here we know, that we're not in his contacts.
&& maybeHistory->loadedAtTop() // And no incoming messages.
&& maybeHistory->loadedAtBottom()) {
update(true);
}
return RequirePremiumState::Unknown;
}
} // namespace Api
+19
View File
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_subscription_option.h"
#include "mtproto/sender.h"
class History;
class ApiWrap;
namespace Main {
@@ -103,10 +104,14 @@ public:
[[nodiscard]] auto subscriptionOptions() const
-> const Data::SubscriptionOptions &;
[[nodiscard]] rpl::producer<> somePremiumRequiredResolved() const;
void resolvePremiumRequired(not_null<UserData*> user);
private:
void reloadPromo();
void reloadStickers();
void reloadCloudSet();
void requestPremiumRequiredSlice();
const not_null<Main::Session*> _session;
MTP::Sender _api;
@@ -143,6 +148,11 @@ private:
Data::SubscriptionOptions _subscriptionOptions;
rpl::event_stream<> _somePremiumRequiredResolved;
base::flat_set<not_null<UserData*>> _resolvePremiumRequiredUsers;
base::flat_set<not_null<UserData*>> _resolvePremiumRequestedUsers;
bool _premiumRequiredRequestScheduled = false;
};
class PremiumGiftCodeOptions final {
@@ -196,4 +206,13 @@ private:
};
enum class RequirePremiumState {
Unknown,
Yes,
No,
};
[[nodiscard]] RequirePremiumState ResolveRequiresPremiumToWrite(
not_null<PeerData*> peer,
History *maybeHistory);
} // namespace Api
@@ -174,14 +174,13 @@ bool SendProgressManager::skipRequest(const Key &key) const {
return true;
}
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
const auto online = user->onlineTill;
if (online == -2) { // last seen recently
const auto lastseen = user->lastseen();
if (lastseen.isRecently()) {
return false;
} else if (online < 0) {
return (-online < recently);
} else {
return (online < recently);
} else if (const auto value = lastseen.onlineTill()) {
return (value < recently);
}
return true;
}
void SendProgressManager::done(mtpRequestId requestId) {
+10 -18
View File
@@ -958,7 +958,9 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
}
const auto self = session().user();
self->onlineTill = base::unixtime::now() + (isOnline ? (config.onlineUpdatePeriod / 1000) : -1);
const auto onlineFor = (config.onlineUpdatePeriod / 1000);
self->updateLastseen(Data::LastseenStatus::OnlineTill(
base::unixtime::now() + (isOnline ? onlineFor : -1)));
session().changes().peerUpdated(
self,
Data::PeerUpdate::Flag::OnlineStatus);
@@ -1243,8 +1245,8 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
if (user && !requestingDifference()) {
user->madeAction(base::unixtime::now());
}
ClearMediaAsExpired(item);
}
ClearMediaAsExpired(item);
}
} else {
// Perhaps it was an unread mention!
@@ -1882,23 +1884,13 @@ void Updates::feedUpdate(const MTPUpdate &update) {
case mtpc_updateUserStatus: {
auto &d = update.c_updateUserStatus();
if (auto user = session().data().userLoaded(d.vuser_id())) {
switch (d.vstatus().type()) {
case mtpc_userStatusEmpty: user->onlineTill = 0; break;
case mtpc_userStatusRecently:
if (user->onlineTill > -10) { // don't modify pseudo-online
user->onlineTill = -2;
}
break;
case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
case mtpc_userStatusOffline: user->onlineTill = d.vstatus().c_userStatusOffline().vwas_online().v; break;
case mtpc_userStatusOnline: user->onlineTill = d.vstatus().c_userStatusOnline().vexpires().v; break;
if (const auto user = session().data().userLoaded(d.vuser_id())) {
const auto now = LastseenFromMTP(d.vstatus(), user->lastseen());
if (user->updateLastseen(now)) {
session().changes().peerUpdated(
user,
Data::PeerUpdate::Flag::OnlineStatus);
}
session().changes().peerUpdated(
user,
Data::PeerUpdate::Flag::OnlineStatus);
session().data().maybeStopWatchForOffline(user);
}
if (UserId(d.vuser_id()) == session().userId()) {
if (d.vstatus().type() == mtpc_userStatusOffline
+89 -14
View File
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_who_reacted.h"
#include "api/api_global_privacy.h"
#include "history/history_item.h"
#include "history/history.h"
#include "data/stickers/data_custom_emoji.h"
@@ -19,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_media_types.h"
#include "data/data_message_reaction_id.h"
#include "data/data_peer_values.h"
#include "lang/lang_keys.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
@@ -36,10 +38,11 @@ namespace {
constexpr auto kContextReactionsLimit = 50;
using Data::ReactionId;
using WhoReadState = Ui::WhoReadState;
struct Peers {
std::vector<WhoReadPeer> list;
bool unknown = false;
WhoReadState state = WhoReadState::Empty;
friend inline bool operator==(
const Peers &a,
@@ -59,7 +62,7 @@ struct PeersWithReactions {
std::vector<PeerWithReaction> list;
std::vector<WhoReadPeer> read;
int fullReactionsCount = 0;
bool unknown = false;
WhoReadState state = WhoReadState::Empty;
friend inline bool operator==(
const PeersWithReactions &a,
@@ -68,7 +71,7 @@ struct PeersWithReactions {
struct CachedRead {
CachedRead()
: data(Peers{ .unknown = true }) {
: data(Peers{ .state = WhoReadState::Unknown }) {
}
rpl::variable<Peers> data;
mtpRequestId requestId = 0;
@@ -76,7 +79,7 @@ struct CachedRead {
struct CachedReacted {
CachedReacted()
: data(PeersWithReactions{ .unknown = true }) {
: data(PeersWithReactions{ .state = WhoReadState::Unknown }) {
}
rpl::variable<PeersWithReactions> data;
mtpRequestId requestId = 0;
@@ -186,6 +189,27 @@ struct State {
context->cachedReacted.erase(j);
}
}, context->subscriptions[session]);
Data::AmPremiumValue(
session
) | rpl::skip(1) | rpl::filter(
rpl::mappers::_1
) | rpl::start_with_next([=] {
for (auto &[item, cache] : context->cachedRead) {
if (cache.data.current().state == Ui::WhoReadState::MyHidden) {
cache.data = Peers{ .state = Ui::WhoReadState::Unknown };
}
}
}, context->subscriptions[session]);
session->api().globalPrivacy().hideReadTime(
) | rpl::skip(1) | rpl::filter(
!rpl::mappers::_1
) | rpl::start_with_next([=] {
for (auto &[item, cache] : context->cachedRead) {
if (cache.data.current().state == Ui::WhoReadState::MyHidden) {
cache.data = Peers{ .state = Ui::WhoReadState::Unknown };
}
}
}, context->subscriptions[session]);
return context;
}
@@ -222,7 +246,38 @@ struct State {
}
const auto context = PreparedContextAt(weak.data(), session);
auto &entry = context->cacheRead(item);
if (!entry.requestId) {
if (entry.requestId) {
} else if (const auto user = item->history()->peer->asUser()) {
entry.requestId = session->api().request(
MTPmessages_GetOutboxReadDate(
user->input,
MTP_int(item->id)
)
).done([=](const MTPOutboxReadDate &result) {
const auto &data = result.data();
auto &entry = context->cacheRead(item);
entry.requestId = 0;
auto parsed = Peers();
parsed.list.push_back({
.peer = user->id,
.date = data.vdate().v,
});
entry.data = std::move(parsed);
}).fail([=](const MTP::Error &error) {
auto &entry = context->cacheRead(item);
entry.requestId = 0;
if (entry.data.current().state == WhoReadState::Unknown) {
const auto &text = error.type();
entry.data = (text == u"YOUR_PRIVACY_RESTRICTED"_q)
? Peers{ .state = WhoReadState::MyHidden }
: (text == u"USER_PRIVACY_RESTRICTED"_q)
? Peers{ .state = WhoReadState::HisHidden }
: (text == u"MESSAGE_TOO_OLD"_q)
? Peers{ .state = WhoReadState::TooOld }
: Peers{ .state = WhoReadState::Empty };
}
}).send();
} else {
entry.requestId = session->api().request(
MTPmessages_GetMessageReadParticipants(
item->history()->peer->input,
@@ -243,8 +298,8 @@ struct State {
}).fail([=] {
auto &entry = context->cacheRead(item);
entry.requestId = 0;
if (entry.data.current().unknown) {
entry.data = Peers();
if (entry.data.current().state == WhoReadState::Unknown) {
entry.data = Peers{ .state = WhoReadState::Empty };
}
}).send();
}
@@ -258,7 +313,7 @@ struct State {
.list = peers.list | ranges::views::transform([](WhoReadPeer peer) {
return PeerWithReaction{ .peerWithDate = peer };
}) | ranges::to_vector,
.unknown = peers.unknown,
.state = peers.state,
};
result.read = std::move(peers.list);
return result;
@@ -319,8 +374,10 @@ struct State {
}).fail([=] {
auto &entry = context->cacheReacted(item, reaction);
entry.requestId = 0;
if (entry.data.current().unknown) {
entry.data = PeersWithReactions();
if (entry.data.current().state == WhoReadState::Unknown) {
entry.data = PeersWithReactions{
.state = WhoReadState::Empty,
};
}
}).send();
}
@@ -336,8 +393,9 @@ struct State {
WhoReactedIds(item, {}, context),
WhoReadIds(item, context)
) | rpl::map([=](PeersWithReactions &&reacted, Peers &&read) {
if (reacted.unknown || read.unknown) {
return PeersWithReactions{ .unknown = true };
if (reacted.state == WhoReadState::Unknown
|| read.state == WhoReadState::Unknown) {
return PeersWithReactions{ .state = WhoReadState::Unknown};
}
auto &list = reacted.list;
for (const auto &peerWithDate : read.list) {
@@ -531,16 +589,17 @@ rpl::producer<Ui::WhoReadContent> WhoReacted(
std::move(
idsWithReactions
) | rpl::start_with_next([=](PeersWithReactions &&peers) {
if (peers.unknown) {
if (peers.state == WhoReadState::Unknown) {
state->userpics.clear();
consumer.put_next(Ui::WhoReadContent{
.type = state->current.type,
.fullReactionsCount = state->current.fullReactionsCount,
.fullReadCount = state->current.fullReadCount,
.unknown = true,
.state = WhoReadState::Unknown,
});
return;
}
state->current.state = peers.state;
state->current.fullReadCount = int(peers.read.size());
state->current.fullReactionsCount = peers.fullReactionsCount;
if (whoReadIds) {
@@ -631,6 +690,22 @@ bool WhoReadExists(not_null<HistoryItem*> item) {
}
const auto history = item->history();
const auto peer = history->peer;
if (const auto user = peer->asUser()) {
if (user->isSelf()
|| user->isBot()
|| user->isServiceUser()
|| user->readDatesPrivate()) {
return false;
}
const auto &appConfig = peer->session().account().appConfig();
const auto expirePeriod = appConfig.get<int>(
"pm_read_date_expire_period",
7 * 86400);
if (item->date() + int64(expirePeriod) <= int64(base::unixtime::now())) {
return false;
}
return true;
}
const auto chat = peer->asChat();
const auto megagroup = peer->asMegagroup();
if ((!chat && !megagroup)