2022-01-26 16:01:40 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
|
|
|
#include "history/history_unread_things.h"
|
|
|
|
|
|
|
|
#include "data/data_session.h"
|
|
|
|
#include "data/data_changes.h"
|
|
|
|
#include "data/data_channel.h"
|
2022-10-07 13:56:07 +00:00
|
|
|
#include "data/data_forum_topic.h"
|
2022-01-26 16:01:40 +00:00
|
|
|
#include "data/data_chat_filters.h"
|
|
|
|
#include "history/history.h"
|
|
|
|
#include "history/history_item.h"
|
|
|
|
#include "main/main_session.h"
|
2022-01-31 15:29:46 +00:00
|
|
|
#include "apiwrap.h"
|
2022-01-26 16:01:40 +00:00
|
|
|
|
|
|
|
namespace HistoryUnreadThings {
|
2022-01-28 09:08:22 +00:00
|
|
|
namespace {
|
|
|
|
|
2022-10-07 13:56:07 +00:00
|
|
|
template <typename Update>
|
|
|
|
[[nodiscard]] typename Update::Flag UpdateFlag(Type type) {
|
|
|
|
using Flag = typename Update::Flag;
|
2022-01-28 09:08:22 +00:00
|
|
|
switch (type) {
|
|
|
|
case Type::Mentions: return Flag::UnreadMentions;
|
|
|
|
case Type::Reactions: return Flag::UnreadReactions;
|
|
|
|
}
|
2022-10-07 13:56:07 +00:00
|
|
|
Unexpected("Type in HistoryUnreadThings::UpdateFlag.");
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] Data::HistoryUpdate::Flag HistoryUpdateFlag(Type type) {
|
|
|
|
return UpdateFlag<Data::HistoryUpdate>(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] Data::TopicUpdate::Flag TopicUpdateFlag(Type type) {
|
|
|
|
return UpdateFlag<Data::TopicUpdate>(type);
|
2022-01-28 09:08:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
2022-01-26 16:01:40 +00:00
|
|
|
|
|
|
|
void Proxy::setCount(int count) {
|
|
|
|
if (!_known) {
|
2022-10-13 10:32:03 +00:00
|
|
|
_thread->setUnreadThingsKnown();
|
2022-01-26 16:01:40 +00:00
|
|
|
}
|
|
|
|
if (!_data) {
|
|
|
|
if (!count) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
createData();
|
|
|
|
}
|
|
|
|
auto &list = resolveList();
|
|
|
|
const auto loaded = list.loadedCount();
|
|
|
|
if (loaded > count) {
|
|
|
|
LOG(("API Warning: "
|
|
|
|
"real count is greater than received unread count"));
|
|
|
|
count = loaded;
|
|
|
|
}
|
|
|
|
const auto had = (list.count() > 0);
|
2022-01-28 09:08:22 +00:00
|
|
|
const auto &other = (_type == Type::Mentions)
|
|
|
|
? _data->reactions
|
|
|
|
: _data->mentions;
|
|
|
|
if (!count && other.count(-1) == 0) {
|
|
|
|
_data = nullptr;
|
|
|
|
} else {
|
|
|
|
list.setCount(count);
|
|
|
|
}
|
2022-01-26 16:01:40 +00:00
|
|
|
const auto has = (count > 0);
|
2022-10-20 08:57:12 +00:00
|
|
|
if (has != had && _thread->inChatList()) {
|
2022-01-28 09:08:22 +00:00
|
|
|
if (_type == Type::Mentions) {
|
2022-10-20 08:57:12 +00:00
|
|
|
_thread->hasUnreadMentionChanged(has);
|
|
|
|
} else if (_type == Type::Reactions) {
|
|
|
|
_thread->hasUnreadReactionChanged(has);
|
2022-01-28 09:08:22 +00:00
|
|
|
}
|
2022-01-26 16:01:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Proxy::add(MsgId msgId, AddType type) {
|
2022-10-13 10:32:03 +00:00
|
|
|
if (const auto history = _thread->asHistory()) {
|
2022-10-07 13:56:07 +00:00
|
|
|
if (history->peer->isBroadcast()) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-01-26 16:01:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!_data) {
|
|
|
|
createData();
|
|
|
|
}
|
|
|
|
auto &list = resolveList();
|
|
|
|
const auto count = list.count();
|
|
|
|
const auto loaded = list.loadedCount();
|
|
|
|
const auto allLoaded = (count >= 0) && (loaded >= count);
|
|
|
|
if (allLoaded) {
|
2022-01-31 15:29:46 +00:00
|
|
|
if (type == AddType::New || !list.contains(msgId)) {
|
2022-01-26 16:01:40 +00:00
|
|
|
list.insert(msgId);
|
|
|
|
setCount(count + 1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (loaded > 0 && type != AddType::New) {
|
|
|
|
list.insert(msgId);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Proxy::erase(MsgId msgId) {
|
|
|
|
if (!_data) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto &list = resolveList();
|
|
|
|
list.erase(msgId);
|
|
|
|
if (const auto count = list.count(); count > 0) {
|
|
|
|
setCount(count - 1);
|
|
|
|
}
|
2022-10-07 13:56:07 +00:00
|
|
|
notifyUpdated();
|
2022-01-28 09:08:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Proxy::clear() {
|
|
|
|
if (!_data || !count()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto &list = resolveList();
|
|
|
|
list.clear();
|
|
|
|
setCount(0);
|
2022-10-07 13:56:07 +00:00
|
|
|
notifyUpdated();
|
2022-01-26 16:01:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 15:29:46 +00:00
|
|
|
void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
|
|
|
if (!alreadyLoaded && _data) {
|
|
|
|
resolveList().clear();
|
|
|
|
}
|
2022-10-13 10:32:03 +00:00
|
|
|
const auto history = _thread->owningHistory();
|
2022-01-26 16:01:40 +00:00
|
|
|
auto fullCount = slice.match([&](
|
|
|
|
const MTPDmessages_messagesNotModified &) {
|
|
|
|
LOG(("API Error: received messages.messagesNotModified! "
|
|
|
|
"(Proxy::addSlice)"));
|
|
|
|
return 0;
|
|
|
|
}, [&](const MTPDmessages_messages &data) {
|
|
|
|
return int(data.vmessages().v.size());
|
|
|
|
}, [&](const MTPDmessages_messagesSlice &data) {
|
|
|
|
return data.vcount().v;
|
|
|
|
}, [&](const MTPDmessages_channelMessages &data) {
|
2022-10-07 13:56:07 +00:00
|
|
|
if (const auto channel = history->peer->asChannel()) {
|
|
|
|
channel->ptsReceived(data.vpts().v);
|
2022-01-26 16:01:40 +00:00
|
|
|
} else {
|
|
|
|
LOG(("API Error: received messages.channelMessages when "
|
|
|
|
"no channel was passed! (Proxy::addSlice)"));
|
|
|
|
}
|
|
|
|
return data.vcount().v;
|
|
|
|
});
|
|
|
|
|
2022-10-13 10:32:03 +00:00
|
|
|
auto &owner = _thread->owner();
|
2022-01-26 16:01:40 +00:00
|
|
|
const auto messages = slice.match([&](
|
|
|
|
const MTPDmessages_messagesNotModified &) {
|
|
|
|
LOG(("API Error: received messages.messagesNotModified! "
|
|
|
|
"(Proxy::addSlice)"));
|
|
|
|
return QVector<MTPMessage>();
|
|
|
|
}, [&](const auto &data) {
|
|
|
|
owner.processUsers(data.vusers());
|
|
|
|
owner.processChats(data.vchats());
|
|
|
|
return data.vmessages().v;
|
|
|
|
});
|
2022-01-31 15:29:46 +00:00
|
|
|
if (!messages.isEmpty() && !_data) {
|
2022-01-26 16:01:40 +00:00
|
|
|
createData();
|
|
|
|
}
|
|
|
|
auto added = false;
|
2022-01-31 15:29:46 +00:00
|
|
|
const auto list = _data ? &resolveList() : nullptr;
|
2022-01-26 16:01:40 +00:00
|
|
|
const auto localFlags = MessageFlags();
|
|
|
|
const auto type = NewMessageType::Existing;
|
|
|
|
for (const auto &message : messages) {
|
2022-10-07 13:56:07 +00:00
|
|
|
const auto item = history->addNewMessage(
|
2022-01-26 16:01:40 +00:00
|
|
|
IdFromMessage(message),
|
|
|
|
message,
|
|
|
|
localFlags,
|
|
|
|
type);
|
|
|
|
const auto is = [&] {
|
|
|
|
switch (_type) {
|
|
|
|
case Type::Mentions: return item->isUnreadMention();
|
|
|
|
case Type::Reactions: return item->hasUnreadReaction();
|
|
|
|
}
|
|
|
|
Unexpected("Type in Proxy::addSlice.");
|
|
|
|
}();
|
|
|
|
if (is) {
|
2022-01-31 15:29:46 +00:00
|
|
|
list->insert(item->id);
|
2022-01-26 16:01:40 +00:00
|
|
|
added = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!added) {
|
2022-01-31 15:29:46 +00:00
|
|
|
fullCount = loadedCount();
|
2022-01-26 16:01:40 +00:00
|
|
|
}
|
|
|
|
setCount(fullCount);
|
2022-10-07 13:56:07 +00:00
|
|
|
notifyUpdated();
|
2022-01-26 16:01:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 15:29:46 +00:00
|
|
|
void Proxy::checkAdd(MsgId msgId, bool resolved) {
|
|
|
|
Expects(_type == Type::Reactions);
|
|
|
|
|
|
|
|
if (!_data) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto &list = resolveList();
|
|
|
|
if (!list.loadedCount() || list.maxLoaded() <= msgId) {
|
|
|
|
return;
|
|
|
|
}
|
2022-10-13 10:32:03 +00:00
|
|
|
const auto history = _thread->owningHistory();
|
2022-01-31 15:29:46 +00:00
|
|
|
const auto peer = history->peer;
|
|
|
|
const auto item = peer->owner().message(peer, msgId);
|
|
|
|
if (item && item->hasUnreadReaction()) {
|
|
|
|
item->addToUnreadThings(AddType::Existing);
|
|
|
|
} else if (!item && !resolved) {
|
|
|
|
peer->session().api().requestMessageData(peer, msgId, [=] {
|
|
|
|
history->unreadReactions().checkAdd(msgId, true);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 13:56:07 +00:00
|
|
|
void Proxy::notifyUpdated() {
|
2022-10-13 10:32:03 +00:00
|
|
|
if (const auto history = _thread->asHistory()) {
|
2022-10-07 13:56:07 +00:00
|
|
|
history->session().changes().historyUpdated(
|
|
|
|
history,
|
|
|
|
HistoryUpdateFlag(_type));
|
2022-10-13 10:32:03 +00:00
|
|
|
} else if (const auto topic = _thread->asTopic()) {
|
2022-10-07 13:56:07 +00:00
|
|
|
topic->session().changes().topicUpdated(
|
|
|
|
topic,
|
|
|
|
TopicUpdateFlag(_type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-26 16:01:40 +00:00
|
|
|
void Proxy::createData() {
|
|
|
|
_data = std::make_unique<All>();
|
|
|
|
if (_known) {
|
|
|
|
_data->mentions.setCount(0);
|
|
|
|
_data->reactions.setCount(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 13:56:07 +00:00
|
|
|
List &Proxy::resolveList() {
|
2022-01-26 16:01:40 +00:00
|
|
|
Expects(_data != nullptr);
|
|
|
|
|
|
|
|
switch (_type) {
|
|
|
|
case Type::Mentions: return _data->mentions;
|
|
|
|
case Type::Reactions: return _data->reactions;
|
|
|
|
}
|
|
|
|
Unexpected("Unread things type in Proxy::resolveList.");
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace HistoryUnreadThings
|