mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 15:43:55 +02:00
Track unread mentions / reactions in topics.
This commit is contained in:
parent
9348039313
commit
2c0b5b3210
22 changed files with 448 additions and 192 deletions
|
@ -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_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -23,6 +24,18 @@ constexpr auto kPreloadIfLess = 5;
|
||||||
constexpr auto kFirstRequestLimit = 10;
|
constexpr auto kFirstRequestLimit = 10;
|
||||||
constexpr auto kNextRequestLimit = 100;
|
constexpr auto kNextRequestLimit = 100;
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<History*> ResolveHistory(
|
||||||
|
not_null<Dialogs::Entry*> entry) {
|
||||||
|
if (const auto history = entry->asHistory()) {
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
const auto topic = entry->asTopic();
|
||||||
|
|
||||||
|
Ensures(topic != nullptr);
|
||||||
|
return topic->history();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
UnreadThings::UnreadThings(not_null<ApiWrap*> api) : _api(api) {
|
UnreadThings::UnreadThings(not_null<ApiWrap*> api) : _api(api) {
|
||||||
|
@ -36,10 +49,11 @@ bool UnreadThings::trackReactions(PeerData *peer) const {
|
||||||
return trackMentions(peer) || (peer && peer->isUser());
|
return trackMentions(peer) || (peer && peer->isUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnreadThings::preloadEnough(History *history) {
|
void UnreadThings::preloadEnough(DialogsEntry *entry) {
|
||||||
if (!history) {
|
if (!entry) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto history = ResolveHistory(entry);
|
||||||
if (trackMentions(history->peer)) {
|
if (trackMentions(history->peer)) {
|
||||||
preloadEnoughMentions(history);
|
preloadEnoughMentions(history);
|
||||||
}
|
}
|
||||||
|
@ -63,40 +77,53 @@ void UnreadThings::mediaAndMentionsRead(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnreadThings::preloadEnoughMentions(not_null<History*> history) {
|
void UnreadThings::preloadEnoughMentions(not_null<DialogsEntry*> entry) {
|
||||||
const auto fullCount = history->unreadMentions().count();
|
const auto fullCount = entry->unreadMentions().count();
|
||||||
const auto loadedCount = history->unreadMentions().loadedCount();
|
const auto loadedCount = entry->unreadMentions().loadedCount();
|
||||||
const auto allLoaded = (fullCount >= 0) && (loadedCount >= fullCount);
|
const auto allLoaded = (fullCount >= 0) && (loadedCount >= fullCount);
|
||||||
if (fullCount >= 0 && loadedCount < kPreloadIfLess && !allLoaded) {
|
if (fullCount >= 0 && loadedCount < kPreloadIfLess && !allLoaded) {
|
||||||
requestMentions(history, loadedCount);
|
requestMentions(entry, loadedCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnreadThings::preloadEnoughReactions(not_null<History*> history) {
|
void UnreadThings::preloadEnoughReactions(not_null<DialogsEntry*> entry) {
|
||||||
const auto fullCount = history->unreadReactions().count();
|
const auto fullCount = entry->unreadReactions().count();
|
||||||
const auto loadedCount = history->unreadReactions().loadedCount();
|
const auto loadedCount = entry->unreadReactions().loadedCount();
|
||||||
const auto allLoaded = (fullCount >= 0) && (loadedCount >= fullCount);
|
const auto allLoaded = (fullCount >= 0) && (loadedCount >= fullCount);
|
||||||
if (fullCount >= 0 && loadedCount < kPreloadIfLess && !allLoaded) {
|
if (fullCount >= 0 && loadedCount < kPreloadIfLess && !allLoaded) {
|
||||||
requestReactions(history, loadedCount);
|
requestReactions(entry, loadedCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnreadThings::requestMentions(not_null<History*> history, int loaded) {
|
void UnreadThings::cancelRequests(not_null<DialogsEntry*> entry) {
|
||||||
if (_mentionsRequests.contains(history)) {
|
if (const auto requestId = _mentionsRequests.take(entry)) {
|
||||||
|
_api->request(*requestId).cancel();
|
||||||
|
}
|
||||||
|
if (const auto requestId = _reactionsRequests.take(entry)) {
|
||||||
|
_api->request(*requestId).cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnreadThings::requestMentions(
|
||||||
|
not_null<DialogsEntry*> entry,
|
||||||
|
int loaded) {
|
||||||
|
if (_mentionsRequests.contains(entry)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto topMsgId = 0;
|
|
||||||
const auto offsetId = std::max(
|
const auto offsetId = std::max(
|
||||||
history->unreadMentions().maxLoaded(),
|
entry->unreadMentions().maxLoaded(),
|
||||||
MsgId(1));
|
MsgId(1));
|
||||||
const auto limit = loaded ? kNextRequestLimit : kFirstRequestLimit;
|
const auto limit = loaded ? kNextRequestLimit : kFirstRequestLimit;
|
||||||
const auto addOffset = loaded ? -(limit + 1) : -limit;
|
const auto addOffset = loaded ? -(limit + 1) : -limit;
|
||||||
const auto maxId = 0;
|
const auto maxId = 0;
|
||||||
const auto minId = 0;
|
const auto minId = 0;
|
||||||
|
const auto history = ResolveHistory(entry);
|
||||||
|
const auto topic = entry->asTopic();
|
||||||
|
using Flag = MTPmessages_GetUnreadMentions::Flag;
|
||||||
const auto requestId = _api->request(MTPmessages_GetUnreadMentions(
|
const auto requestId = _api->request(MTPmessages_GetUnreadMentions(
|
||||||
MTP_flags(0),
|
MTP_flags(topic ? Flag::f_top_msg_id : Flag()),
|
||||||
history->peer->input,
|
history->peer->input,
|
||||||
MTP_int(topMsgId),
|
MTP_int(topic ? topic->rootId() : 0),
|
||||||
MTP_int(offsetId),
|
MTP_int(offsetId),
|
||||||
MTP_int(addOffset),
|
MTP_int(addOffset),
|
||||||
MTP_int(limit),
|
MTP_int(limit),
|
||||||
|
@ -111,22 +138,26 @@ void UnreadThings::requestMentions(not_null<History*> history, int loaded) {
|
||||||
_mentionsRequests.emplace(history, requestId);
|
_mentionsRequests.emplace(history, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnreadThings::requestReactions(not_null<History*> history, int loaded) {
|
void UnreadThings::requestReactions(
|
||||||
if (_reactionsRequests.contains(history)) {
|
not_null<DialogsEntry*> entry,
|
||||||
|
int loaded) {
|
||||||
|
if (_reactionsRequests.contains(entry)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto topMsgId = 0;
|
|
||||||
const auto offsetId = loaded
|
const auto offsetId = loaded
|
||||||
? std::max(history->unreadReactions().maxLoaded(), MsgId(1))
|
? std::max(entry->unreadReactions().maxLoaded(), MsgId(1))
|
||||||
: MsgId(1);
|
: MsgId(1);
|
||||||
const auto limit = loaded ? kNextRequestLimit : kFirstRequestLimit;
|
const auto limit = loaded ? kNextRequestLimit : kFirstRequestLimit;
|
||||||
const auto addOffset = loaded ? -(limit + 1) : -limit;
|
const auto addOffset = loaded ? -(limit + 1) : -limit;
|
||||||
const auto maxId = 0;
|
const auto maxId = 0;
|
||||||
const auto minId = 0;
|
const auto minId = 0;
|
||||||
|
const auto history = ResolveHistory(entry);
|
||||||
|
const auto topic = entry->asTopic();
|
||||||
|
using Flag = MTPmessages_GetUnreadReactions::Flag;
|
||||||
const auto requestId = _api->request(MTPmessages_GetUnreadReactions(
|
const auto requestId = _api->request(MTPmessages_GetUnreadReactions(
|
||||||
MTP_flags(0),
|
MTP_flags(topic ? Flag::f_top_msg_id : Flag()),
|
||||||
history->peer->input,
|
history->peer->input,
|
||||||
MTP_int(topMsgId),
|
MTP_int(topic ? topic->rootId() : 0),
|
||||||
MTP_int(offsetId),
|
MTP_int(offsetId),
|
||||||
MTP_int(addOffset),
|
MTP_int(addOffset),
|
||||||
MTP_int(limit),
|
MTP_int(limit),
|
||||||
|
|
|
@ -7,37 +7,44 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class History;
|
|
||||||
class ApiWrap;
|
class ApiWrap;
|
||||||
class PeerData;
|
class PeerData;
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Entry;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
|
||||||
class UnreadThings final {
|
class UnreadThings final {
|
||||||
public:
|
public:
|
||||||
|
using DialogsEntry = Dialogs::Entry;
|
||||||
|
|
||||||
explicit UnreadThings(not_null<ApiWrap*> api);
|
explicit UnreadThings(not_null<ApiWrap*> api);
|
||||||
|
|
||||||
[[nodiscard]] bool trackMentions(PeerData *peer) const;
|
[[nodiscard]] bool trackMentions(PeerData *peer) const;
|
||||||
[[nodiscard]] bool trackReactions(PeerData *peer) const;
|
[[nodiscard]] bool trackReactions(PeerData *peer) const;
|
||||||
|
|
||||||
void preloadEnough(History *history);
|
void preloadEnough(DialogsEntry *entry);
|
||||||
|
|
||||||
void mediaAndMentionsRead(
|
void mediaAndMentionsRead(
|
||||||
const base::flat_set<MsgId> &readIds,
|
const base::flat_set<MsgId> &readIds,
|
||||||
ChannelData *channel = nullptr);
|
ChannelData *channel = nullptr);
|
||||||
|
|
||||||
private:
|
void cancelRequests(not_null<DialogsEntry*> entry);
|
||||||
void preloadEnoughMentions(not_null<History*> history);
|
|
||||||
void preloadEnoughReactions(not_null<History*> history);
|
|
||||||
|
|
||||||
void requestMentions(not_null<History*> history, int loaded);
|
private:
|
||||||
void requestReactions(not_null<History*> history, int loaded);
|
void preloadEnoughMentions(not_null<DialogsEntry*> entry);
|
||||||
|
void preloadEnoughReactions(not_null<DialogsEntry*> entry);
|
||||||
|
|
||||||
|
void requestMentions(not_null<DialogsEntry*> entry, int loaded);
|
||||||
|
void requestReactions(not_null<DialogsEntry*> entry, int loaded);
|
||||||
|
|
||||||
const not_null<ApiWrap*> _api;
|
const not_null<ApiWrap*> _api;
|
||||||
|
|
||||||
base::flat_map<not_null<History*>, mtpRequestId> _mentionsRequests;
|
base::flat_map<not_null<DialogsEntry*>, mtpRequestId> _mentionsRequests;
|
||||||
base::flat_map<not_null<History*>, mtpRequestId> _reactionsRequests;
|
base::flat_map<not_null<DialogsEntry*>, mtpRequestId> _reactionsRequests;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,35 @@ rpl::producer<HistoryUpdate> Changes::realtimeHistoryUpdates(
|
||||||
return _historyChanges.realtimeUpdates(flag);
|
return _historyChanges.realtimeUpdates(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Changes::topicUpdated(
|
||||||
|
not_null<ForumTopic*> topic,
|
||||||
|
TopicUpdate::Flags flags) {
|
||||||
|
_topicChanges.updated(topic, flags);
|
||||||
|
scheduleNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<TopicUpdate> Changes::topicUpdates(
|
||||||
|
TopicUpdate::Flags flags) const {
|
||||||
|
return _topicChanges.updates(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<TopicUpdate> Changes::topicUpdates(
|
||||||
|
not_null<ForumTopic*> topic,
|
||||||
|
TopicUpdate::Flags flags) const {
|
||||||
|
return _topicChanges.updates(topic, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<TopicUpdate> Changes::topicFlagsValue(
|
||||||
|
not_null<ForumTopic*> topic,
|
||||||
|
TopicUpdate::Flags flags) const {
|
||||||
|
return _topicChanges.flagsValue(topic, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<TopicUpdate> Changes::realtimeTopicUpdates(
|
||||||
|
TopicUpdate::Flag flag) const {
|
||||||
|
return _topicChanges.realtimeUpdates(flag);
|
||||||
|
}
|
||||||
|
|
||||||
void Changes::messageUpdated(
|
void Changes::messageUpdated(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
MessageUpdate::Flags flags) {
|
MessageUpdate::Flags flags) {
|
||||||
|
|
|
@ -21,9 +21,7 @@ namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
namespace Data {
|
namespace Data::details {
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template <typename Flag>
|
template <typename Flag>
|
||||||
inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) {
|
inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) {
|
||||||
|
@ -35,7 +33,11 @@ inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace details
|
} // namespace Data::details
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
class ForumTopic;
|
||||||
|
|
||||||
struct NameUpdate {
|
struct NameUpdate {
|
||||||
NameUpdate(
|
NameUpdate(
|
||||||
|
@ -139,6 +141,24 @@ struct HistoryUpdate {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TopicUpdate {
|
||||||
|
enum class Flag : uint32 {
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
UnreadView = (1U << 1),
|
||||||
|
UnreadMentions = (1U << 2),
|
||||||
|
UnreadReactions = (1U << 3),
|
||||||
|
|
||||||
|
LastUsedBit = (1U << 3),
|
||||||
|
};
|
||||||
|
using Flags = base::flags<Flag>;
|
||||||
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
||||||
|
not_null<ForumTopic*> topic;
|
||||||
|
Flags flags = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct MessageUpdate {
|
struct MessageUpdate {
|
||||||
enum class Flag : uint32 {
|
enum class Flag : uint32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
@ -219,6 +239,20 @@ public:
|
||||||
[[nodiscard]] rpl::producer<HistoryUpdate> realtimeHistoryUpdates(
|
[[nodiscard]] rpl::producer<HistoryUpdate> realtimeHistoryUpdates(
|
||||||
HistoryUpdate::Flag flag) const;
|
HistoryUpdate::Flag flag) const;
|
||||||
|
|
||||||
|
void topicUpdated(
|
||||||
|
not_null<ForumTopic*> topic,
|
||||||
|
TopicUpdate::Flags flags);
|
||||||
|
[[nodiscard]] rpl::producer<TopicUpdate> topicUpdates(
|
||||||
|
TopicUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<TopicUpdate> topicUpdates(
|
||||||
|
not_null<ForumTopic*> topic,
|
||||||
|
TopicUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<TopicUpdate> topicFlagsValue(
|
||||||
|
not_null<ForumTopic*> topic,
|
||||||
|
TopicUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<TopicUpdate> realtimeTopicUpdates(
|
||||||
|
TopicUpdate::Flag flag) const;
|
||||||
|
|
||||||
void messageUpdated(
|
void messageUpdated(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
MessageUpdate::Flags flags);
|
MessageUpdate::Flags flags);
|
||||||
|
@ -292,6 +326,7 @@ private:
|
||||||
rpl::event_stream<NameUpdate> _nameStream;
|
rpl::event_stream<NameUpdate> _nameStream;
|
||||||
Manager<PeerData, PeerUpdate> _peerChanges;
|
Manager<PeerData, PeerUpdate> _peerChanges;
|
||||||
Manager<History, HistoryUpdate> _historyChanges;
|
Manager<History, HistoryUpdate> _historyChanges;
|
||||||
|
Manager<ForumTopic, TopicUpdate> _topicChanges;
|
||||||
Manager<HistoryItem, MessageUpdate> _messageChanges;
|
Manager<HistoryItem, MessageUpdate> _messageChanges;
|
||||||
Manager<Dialogs::Entry, EntryUpdate> _entryChanges;
|
Manager<Dialogs::Entry, EntryUpdate> _entryChanges;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
#include "history/history_unread_things.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -188,12 +189,6 @@ void Forum::applyTopicAdded(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Forum::applyTopicRemoved(MsgId rootId) {
|
|
||||||
//if (const auto i = _topics.find(rootId)) {
|
|
||||||
// _topics.erase(i);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
MsgId Forum::reserveCreatingId(
|
MsgId Forum::reserveCreatingId(
|
||||||
const QString &title,
|
const QString &title,
|
||||||
int32 colorId,
|
int32 colorId,
|
||||||
|
@ -238,7 +233,13 @@ void Forum::created(MsgId rootId, MsgId realId) {
|
||||||
owner().notifyItemIdChange({ id, rootId });
|
owner().notifyItemIdChange({ id, rootId });
|
||||||
}
|
}
|
||||||
|
|
||||||
ForumTopic *Forum::topicFor(not_null<HistoryItem*> item) {
|
void Forum::clearAllUnreadMentions() {
|
||||||
|
for (const auto &[rootId, topic] : _topics) {
|
||||||
|
topic->unreadMentions().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ForumTopic *Forum::topicFor(not_null<const HistoryItem*> item) {
|
||||||
const auto maybe = topicFor(item->replyToTop());
|
const auto maybe = topicFor(item->replyToTop());
|
||||||
return maybe ? maybe : topicFor(item->topicRootId());
|
return maybe ? maybe : topicFor(item->topicRootId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,9 +45,8 @@ public:
|
||||||
const QString &title,
|
const QString &title,
|
||||||
int32 colorId,
|
int32 colorId,
|
||||||
DocumentId iconId);
|
DocumentId iconId);
|
||||||
void applyTopicRemoved(MsgId rootId);
|
|
||||||
void applyTopicCreated(MsgId rootId, MsgId realId);
|
void applyTopicCreated(MsgId rootId, MsgId realId);
|
||||||
[[nodiscard]] ForumTopic *topicFor(not_null<HistoryItem*> item);
|
[[nodiscard]] ForumTopic *topicFor(not_null<const HistoryItem*> item);
|
||||||
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
||||||
|
|
||||||
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
||||||
|
@ -60,6 +59,8 @@ public:
|
||||||
[[nodiscard]] bool creating(MsgId rootId) const;
|
[[nodiscard]] bool creating(MsgId rootId) const;
|
||||||
void created(MsgId rootId, MsgId realId);
|
void created(MsgId rootId, MsgId realId);
|
||||||
|
|
||||||
|
void clearAllUnreadMentions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct TopicRequest {
|
struct TopicRequest {
|
||||||
mtpRequestId id = 0;
|
mtpRequestId id = 0;
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
|
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "data/data_forum.h"
|
#include "data/data_forum.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_replies_list.h"
|
#include "data/data_replies_list.h"
|
||||||
|
@ -17,9 +18,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "dialogs/ui/dialogs_layout.h"
|
#include "dialogs/ui/dialogs_layout.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "api/api_unread_things.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
#include "history/history_unread_things.h"
|
||||||
#include "history/view/history_view_item_preview.h"
|
#include "history/view/history_view_item_preview.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/color_int_conversion.h"
|
#include "ui/color_int_conversion.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
@ -28,6 +33,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtSvg/QSvgRenderer>
|
#include <QtSvg/QSvgRenderer>
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using UpdateFlag = TopicUpdate::Flag;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
const base::flat_map<int32, QString> &ForumTopicIcons() {
|
const base::flat_map<int32, QString> &ForumTopicIcons() {
|
||||||
static const auto Result = base::flat_map<int32, QString>{
|
static const auto Result = base::flat_map<int32, QString>{
|
||||||
|
@ -135,6 +145,7 @@ ForumTopic::ForumTopic(not_null<History*> history, MsgId rootId)
|
||||||
_replies->unreadCountValue(
|
_replies->unreadCountValue(
|
||||||
) | rpl::combine_previous(
|
) | rpl::combine_previous(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
|
session().changes().topicUpdated(this, UpdateFlag::UnreadView);
|
||||||
return inChatList();
|
return inChatList();
|
||||||
}) | rpl::start_with_next([=](
|
}) | rpl::start_with_next([=](
|
||||||
std::optional<int> previous,
|
std::optional<int> previous,
|
||||||
|
@ -145,7 +156,9 @@ ForumTopic::ForumTopic(not_null<History*> history, MsgId rootId)
|
||||||
}, _replies->lifetime());
|
}, _replies->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
ForumTopic::~ForumTopic() = default;
|
ForumTopic::~ForumTopic() {
|
||||||
|
session().api().unreadThings().cancelRequests(this);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Data::RepliesList> ForumTopic::replies() const {
|
std::shared_ptr<Data::RepliesList> ForumTopic::replies() const {
|
||||||
return _replies;
|
return _replies;
|
||||||
|
@ -203,6 +216,8 @@ void ForumTopic::applyTopic(const MTPForumTopic &topic) {
|
||||||
#if 0 // #TODO forum unread mark
|
#if 0 // #TODO forum unread mark
|
||||||
setUnreadMark(data.is_unread_mark());
|
setUnreadMark(data.is_unread_mark());
|
||||||
#endif
|
#endif
|
||||||
|
unreadMentions().setCount(data.vunread_mentions_count().v);
|
||||||
|
unreadReactions().setCount(data.vunread_reactions_count().v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForumTopic::indexTitleParts() {
|
void ForumTopic::indexTitleParts() {
|
||||||
|
@ -470,7 +485,7 @@ bool ForumTopic::unreadCountKnown() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForumTopic::setUnreadMark(bool unread) {
|
void ForumTopic::setUnreadMark(bool unread) {
|
||||||
if (_unreadMark == unread) {
|
if (unreadMark() == unread) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto noUnreadMessages = !unreadCount();
|
const auto noUnreadMessages = !unreadCount();
|
||||||
|
@ -478,13 +493,18 @@ void ForumTopic::setUnreadMark(bool unread) {
|
||||||
if (inChatList() && noUnreadMessages) {
|
if (inChatList() && noUnreadMessages) {
|
||||||
updateChatListEntry();
|
updateChatListEntry();
|
||||||
}
|
}
|
||||||
|
session().changes().topicUpdated(this, UpdateFlag::UnreadView);
|
||||||
});
|
});
|
||||||
const auto notifier = unreadStateChangeNotifier(noUnreadMessages);
|
const auto notifier = unreadStateChangeNotifier(noUnreadMessages);
|
||||||
_unreadMark = unread;
|
if (unread) {
|
||||||
|
_flags |= Flag::UnreadMark;
|
||||||
|
} else {
|
||||||
|
_flags &= ~Flag::UnreadMark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ForumTopic::unreadMark() const {
|
bool ForumTopic::unreadMark() const {
|
||||||
return _unreadMark;
|
return (_flags & Flag::UnreadMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ForumTopic::chatListUnreadCount() const {
|
int ForumTopic::chatListUnreadCount() const {
|
||||||
|
@ -503,7 +523,7 @@ Dialogs::UnreadState ForumTopic::unreadStateFor(
|
||||||
int count,
|
int count,
|
||||||
bool known) const {
|
bool known) const {
|
||||||
auto result = Dialogs::UnreadState();
|
auto result = Dialogs::UnreadState();
|
||||||
const auto mark = !count && _unreadMark;
|
const auto mark = !count && unreadMark();
|
||||||
const auto muted = _history->mute();
|
const auto muted = _history->mute();
|
||||||
result.messages = count;
|
result.messages = count;
|
||||||
result.messagesMuted = muted ? count : 0;
|
result.messagesMuted = muted ? count : 0;
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "dialogs/dialogs_entry.h"
|
#include "dialogs/dialogs_entry.h"
|
||||||
#include "dialogs/ui/dialogs_message_view.h"
|
#include "dialogs/ui/dialogs_message_view.h"
|
||||||
|
#include "base/flags.h"
|
||||||
|
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
|
|
||||||
|
@ -111,6 +112,11 @@ public:
|
||||||
Dialogs::Ui::MessageView lastItemDialogsView;
|
Dialogs::Ui::MessageView lastItemDialogsView;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class Flag : uchar {
|
||||||
|
UnreadMark = 0x01,
|
||||||
|
};
|
||||||
|
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||||
|
|
||||||
void indexTitleParts();
|
void indexTitleParts();
|
||||||
void validateDefaultIcon() const;
|
void validateDefaultIcon() const;
|
||||||
void applyTopicTopMessage(MsgId topMessageId);
|
void applyTopicTopMessage(MsgId topMessageId);
|
||||||
|
@ -144,7 +150,7 @@ private:
|
||||||
std::optional<HistoryItem*> _lastServerMessage;
|
std::optional<HistoryItem*> _lastServerMessage;
|
||||||
std::optional<HistoryItem*> _chatListMessage;
|
std::optional<HistoryItem*> _chatListMessage;
|
||||||
base::flat_set<FullMsgId> _requestedGroups;
|
base::flat_set<FullMsgId> _requestedGroups;
|
||||||
bool _unreadMark = false;
|
base::flags<Flag> _flags;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
|
|
@ -156,18 +156,18 @@ private:
|
||||||
not_null<History*> history;
|
not_null<History*> history;
|
||||||
MsgId rootId = 0;
|
MsgId rootId = 0;
|
||||||
|
|
||||||
friend inline constexpr auto operator<=>(
|
friend inline auto operator<=>(
|
||||||
GroupRequestKey,
|
GroupRequestKey,
|
||||||
GroupRequestKey) = default;
|
GroupRequestKey) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Arg>
|
template <typename Arg>
|
||||||
static auto ReplaceReplyTo(Arg arg, MsgId replyTo) {
|
static auto ReplaceReplyTo(Arg arg, MsgId replyTo) {
|
||||||
return arg;
|
if constexpr (std::is_same_v<Arg, ReplyToPlaceholder>) {
|
||||||
}
|
return MTP_int(replyTo);
|
||||||
template <>
|
} else {
|
||||||
static auto ReplaceReplyTo(ReplyToPlaceholder, MsgId replyTo) {
|
return arg;
|
||||||
return MTP_int(replyTo);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void readInboxTill(not_null<History*> history, MsgId tillId, bool force);
|
void readInboxTill(not_null<History*> history, MsgId tillId, bool force);
|
||||||
|
|
|
@ -18,8 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
#include "ui/text/text_options.h"
|
#include "ui/text/text_options.h"
|
||||||
#include "history/history_item.h"
|
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "history/history_unread_things.h"
|
||||||
#include "styles/style_dialogs.h" // st::dialogsTextWidthMin
|
#include "styles/style_dialogs.h" // st::dialogsTextWidthMin
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
@ -49,6 +50,8 @@ Entry::Entry(not_null<Data::Session*> owner, Type type)
|
||||||
, _type(type) {
|
, _type(type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entry::~Entry() = default;
|
||||||
|
|
||||||
Data::Session &Entry::owner() const {
|
Data::Session &Entry::owner() const {
|
||||||
return *_owner;
|
return *_owner;
|
||||||
}
|
}
|
||||||
|
@ -102,19 +105,30 @@ void Entry::cachePinnedIndex(FilterId filterId, int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::cacheTopPromoted(bool promoted) {
|
void Entry::cacheTopPromoted(bool promoted) {
|
||||||
if (_isTopPromoted == promoted) {
|
if (isTopPromoted() == promoted) {
|
||||||
return;
|
return;
|
||||||
|
} else if (promoted) {
|
||||||
|
_flags |= Flag::IsTopPromoted;
|
||||||
|
} else {
|
||||||
|
_flags &= ~Flag::IsTopPromoted;
|
||||||
}
|
}
|
||||||
_isTopPromoted = promoted;
|
|
||||||
updateChatListSortPosition();
|
updateChatListSortPosition();
|
||||||
updateChatListEntry();
|
updateChatListEntry();
|
||||||
if (!_isTopPromoted) {
|
if (!isTopPromoted()) {
|
||||||
updateChatListExistence();
|
updateChatListExistence();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Entry::isTopPromoted() const {
|
bool Entry::isTopPromoted() const {
|
||||||
return _isTopPromoted;
|
return (_flags & Flag::IsTopPromoted);
|
||||||
|
}
|
||||||
|
|
||||||
|
const base::flat_set<MsgId> &Entry::unreadMentionsIds() const {
|
||||||
|
if (!_unreadThings) {
|
||||||
|
static const auto Result = base::flat_set<MsgId>();
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
return _unreadThings->mentions.ids();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Entry::needUpdateInChatList() const {
|
bool Entry::needUpdateInChatList() const {
|
||||||
|
@ -198,6 +212,42 @@ TimeId Entry::adjustedChatListTimeId() const {
|
||||||
return chatListTimeId();
|
return chatListTimeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entry::setUnreadThingsKnown() {
|
||||||
|
_flags |= Flag::UnreadThingsKnown;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryUnreadThings::Proxy Entry::unreadMentions() {
|
||||||
|
return {
|
||||||
|
this,
|
||||||
|
_unreadThings,
|
||||||
|
HistoryUnreadThings::Type::Mentions,
|
||||||
|
!!(_flags & Flag::UnreadThingsKnown),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryUnreadThings::ConstProxy Entry::unreadMentions() const {
|
||||||
|
return {
|
||||||
|
_unreadThings ? &_unreadThings->mentions : nullptr,
|
||||||
|
!!(_flags & Flag::UnreadThingsKnown),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryUnreadThings::Proxy Entry::unreadReactions() {
|
||||||
|
return {
|
||||||
|
this,
|
||||||
|
_unreadThings,
|
||||||
|
HistoryUnreadThings::Type::Reactions,
|
||||||
|
!!(_flags & Flag::UnreadThingsKnown),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryUnreadThings::ConstProxy Entry::unreadReactions() const {
|
||||||
|
return {
|
||||||
|
_unreadThings ? &_unreadThings->reactions : nullptr,
|
||||||
|
!!(_flags & Flag::UnreadThingsKnown),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void Entry::changedChatListPinHook() {
|
void Entry::changedChatListPinHook() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,13 @@ class ForumTopic;
|
||||||
class CloudImageView;
|
class CloudImageView;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace HistoryUnreadThings {
|
||||||
|
enum class AddType;
|
||||||
|
struct All;
|
||||||
|
class Proxy;
|
||||||
|
class ConstProxy;
|
||||||
|
} // namespace HistoryUnreadThings
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
@ -108,7 +115,7 @@ public:
|
||||||
Entry(not_null<Data::Session*> owner, Type type);
|
Entry(not_null<Data::Session*> owner, Type type);
|
||||||
Entry(const Entry &other) = delete;
|
Entry(const Entry &other) = delete;
|
||||||
Entry &operator=(const Entry &other) = delete;
|
Entry &operator=(const Entry &other) = delete;
|
||||||
virtual ~Entry() = default;
|
virtual ~Entry();
|
||||||
|
|
||||||
[[nodiscard]] Data::Session &owner() const;
|
[[nodiscard]] Data::Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
@ -154,6 +161,12 @@ public:
|
||||||
bool needUpdateInChatList() const;
|
bool needUpdateInChatList() const;
|
||||||
virtual TimeId adjustedChatListTimeId() const;
|
virtual TimeId adjustedChatListTimeId() const;
|
||||||
|
|
||||||
|
void setUnreadThingsKnown();
|
||||||
|
[[nodiscard]] HistoryUnreadThings::Proxy unreadMentions();
|
||||||
|
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const;
|
||||||
|
[[nodiscard]] HistoryUnreadThings::Proxy unreadReactions();
|
||||||
|
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadReactions() const;
|
||||||
|
|
||||||
virtual int fixedOnTopIndex() const = 0;
|
virtual int fixedOnTopIndex() const = 0;
|
||||||
static constexpr auto kArchiveFixOnTopIndex = 1;
|
static constexpr auto kArchiveFixOnTopIndex = 1;
|
||||||
static constexpr auto kTopPromotionFixOnTopIndex = 2;
|
static constexpr auto kTopPromotionFixOnTopIndex = 2;
|
||||||
|
@ -209,7 +222,15 @@ protected:
|
||||||
|
|
||||||
void cacheTopPromoted(bool promoted);
|
void cacheTopPromoted(bool promoted);
|
||||||
|
|
||||||
|
[[nodiscard]] const base::flat_set<MsgId> &unreadMentionsIds() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class Flag : uchar {
|
||||||
|
IsTopPromoted = 0x01,
|
||||||
|
UnreadThingsKnown = 0x02,
|
||||||
|
};
|
||||||
|
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||||
|
|
||||||
virtual void changedChatListPinHook();
|
virtual void changedChatListPinHook();
|
||||||
void pinnedIndexChanged(FilterId filterId, int was, int now);
|
void pinnedIndexChanged(FilterId filterId, int was, int now);
|
||||||
[[nodiscard]] uint64 computeSortPosition(FilterId filterId) const;
|
[[nodiscard]] uint64 computeSortPosition(FilterId filterId) const;
|
||||||
|
@ -225,11 +246,12 @@ private:
|
||||||
uint64 _sortKeyInChatList = 0;
|
uint64 _sortKeyInChatList = 0;
|
||||||
uint64 _sortKeyByDate = 0;
|
uint64 _sortKeyByDate = 0;
|
||||||
base::flat_map<FilterId, int> _pinnedIndex;
|
base::flat_map<FilterId, int> _pinnedIndex;
|
||||||
|
std::unique_ptr<HistoryUnreadThings::All> _unreadThings;
|
||||||
mutable Ui::PeerBadge _chatListBadge;
|
mutable Ui::PeerBadge _chatListBadge;
|
||||||
mutable Ui::Text::String _chatListNameText;
|
mutable Ui::Text::String _chatListNameText;
|
||||||
mutable int _chatListNameVersion = 0;
|
mutable int _chatListNameVersion = 0;
|
||||||
TimeId _timeId = 0;
|
TimeId _timeId = 0;
|
||||||
bool _isTopPromoted = false;
|
base::flags<Flag> _flags;
|
||||||
const Type _type;
|
const Type _type;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -916,11 +916,12 @@ void RowPainter::Paint(
|
||||||
? base::unixtime::parse(cloudDraft->date)
|
? base::unixtime::parse(cloudDraft->date)
|
||||||
: QDateTime();
|
: QDateTime();
|
||||||
}();
|
}();
|
||||||
const auto displayMentionBadge = history
|
const auto displayMentionBadge = (history
|
||||||
&& history->unreadMentions().has();
|
&& history->unreadMentions().has())
|
||||||
|
|| (topic && topic->unreadMentions().has());
|
||||||
const auto displayReactionBadge = !displayMentionBadge
|
const auto displayReactionBadge = !displayMentionBadge
|
||||||
&& history
|
&& ((history && history->unreadReactions().has())
|
||||||
&& history->unreadReactions().has();
|
|| (topic && topic->unreadReactions().has()));
|
||||||
const auto mentionOrReactionMuted = (entry->folder() != nullptr)
|
const auto mentionOrReactionMuted = (entry->folder() != nullptr)
|
||||||
|| (!displayMentionBadge && unreadMuted);
|
|| (!displayMentionBadge && unreadMuted);
|
||||||
const auto displayUnreadCounter = [&] {
|
const auto displayUnreadCounter = [&] {
|
||||||
|
|
|
@ -161,14 +161,8 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
|
||||||
if (IsClientMsgId(item->id)) {
|
if (IsClientMsgId(item->id)) {
|
||||||
unregisterClientSideMessage(item);
|
unregisterClientSideMessage(item);
|
||||||
}
|
}
|
||||||
if (const auto forum = peer->forum()) {
|
if (const auto topic = item->topic()) {
|
||||||
if (const auto topic = forum->topicFor(item)) {
|
topic->applyItemRemoved(item->id);
|
||||||
if (topic->rootId() == item->id) {
|
|
||||||
forum->applyTopicRemoved(item->id);
|
|
||||||
} else {
|
|
||||||
topic->applyItemRemoved(item->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (const auto chat = peer->asChat()) {
|
if (const auto chat = peer->asChat()) {
|
||||||
if (const auto to = chat->getMigrateToChannel()) {
|
if (const auto to = chat->getMigrateToChannel()) {
|
||||||
|
@ -705,40 +699,25 @@ not_null<HistoryItem*> History::addNewLocalMessage(
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::setUnreadThingsKnown() {
|
void History::clearUnreadMentionsFor(MsgId topicRootId) {
|
||||||
_flags |= Flag::UnreadThingsKnown;
|
const auto &ids = unreadMentionsIds();
|
||||||
}
|
if (ids.empty()) {
|
||||||
|
return;
|
||||||
HistoryUnreadThings::Proxy History::unreadMentions() {
|
}
|
||||||
return {
|
const auto owner = &this->owner();
|
||||||
this,
|
const auto peerId = peer->id;
|
||||||
_unreadThings,
|
auto items = base::flat_set<MsgId>();
|
||||||
HistoryUnreadThings::Type::Mentions,
|
items.reserve(ids.size());
|
||||||
!!(_flags & Flag::UnreadThingsKnown),
|
for (const auto &id : ids) {
|
||||||
};
|
if (const auto item = owner->message(peerId, id)) {
|
||||||
}
|
if (item->topicRootId() == topicRootId) {
|
||||||
|
items.emplace(id);
|
||||||
HistoryUnreadThings::ConstProxy History::unreadMentions() const {
|
}
|
||||||
return {
|
}
|
||||||
_unreadThings ? &_unreadThings->mentions : nullptr,
|
}
|
||||||
!!(_flags & Flag::UnreadThingsKnown),
|
for (const auto &id : items) {
|
||||||
};
|
unreadMentions().erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryUnreadThings::Proxy History::unreadReactions() {
|
|
||||||
return {
|
|
||||||
this,
|
|
||||||
_unreadThings,
|
|
||||||
HistoryUnreadThings::Type::Reactions,
|
|
||||||
!!(_flags & Flag::UnreadThingsKnown),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryUnreadThings::ConstProxy History::unreadReactions() const {
|
|
||||||
return {
|
|
||||||
_unreadThings ? &_unreadThings->reactions : nullptr,
|
|
||||||
!!(_flags & Flag::UnreadThingsKnown),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<HistoryItem*> History::addNewToBack(
|
not_null<HistoryItem*> History::addNewToBack(
|
||||||
|
@ -1084,14 +1063,12 @@ void History::applyServiceChanges(
|
||||||
data.vicon_emoji_id().value_or(DocumentId()));
|
data.vicon_emoji_id().value_or(DocumentId()));
|
||||||
}
|
}
|
||||||
}, [&](const MTPDmessageActionTopicEdit &data) {
|
}, [&](const MTPDmessageActionTopicEdit &data) {
|
||||||
if (const auto forum = peer->forum()) {
|
if (const auto topic = item->topic()) {
|
||||||
if (const auto topic = forum->topicFor(item)) {
|
if (const auto &title = data.vtitle()) {
|
||||||
if (const auto &title = data.vtitle()) {
|
topic->applyTitle(qs(*title));
|
||||||
topic->applyTitle(qs(*title));
|
}
|
||||||
}
|
if (const auto icon = data.vicon_emoji_id()) {
|
||||||
if (const auto icon = data.vicon_emoji_id()) {
|
topic->applyIconId(icon->v);
|
||||||
topic->applyIconId(icon->v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [](const auto &) {
|
}, [](const auto &) {
|
||||||
|
@ -1154,10 +1131,8 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||||
if (!folderKnown()) {
|
if (!folderKnown()) {
|
||||||
owner().histories().requestDialogEntry(this);
|
owner().histories().requestDialogEntry(this);
|
||||||
}
|
}
|
||||||
if (const auto forum = peer->forum()) {
|
if (const auto topic = item->topic()) {
|
||||||
if (const auto topic = forum->topicFor(item)) {
|
topic->applyItemAdded(item);
|
||||||
topic->applyItemAdded(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,6 @@ class HistoryService;
|
||||||
struct HistoryMessageMarkupData;
|
struct HistoryMessageMarkupData;
|
||||||
class HistoryMainElementDelegateMixin;
|
class HistoryMainElementDelegateMixin;
|
||||||
|
|
||||||
namespace HistoryUnreadThings {
|
|
||||||
enum class AddType;
|
|
||||||
struct All;
|
|
||||||
class Proxy;
|
|
||||||
class ConstProxy;
|
|
||||||
} // namespace HistoryUnreadThings
|
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
@ -337,12 +330,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearLastKeyboard();
|
void clearLastKeyboard();
|
||||||
|
void clearUnreadMentionsFor(MsgId topicRootId);
|
||||||
void setUnreadThingsKnown();
|
|
||||||
[[nodiscard]] HistoryUnreadThings::Proxy unreadMentions();
|
|
||||||
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const;
|
|
||||||
[[nodiscard]] HistoryUnreadThings::Proxy unreadReactions();
|
|
||||||
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadReactions() const;
|
|
||||||
|
|
||||||
Data::Draft *draft(Data::DraftKey key) const;
|
Data::Draft *draft(Data::DraftKey key) const;
|
||||||
void setDraft(Data::DraftKey key, std::unique_ptr<Data::Draft> &&draft);
|
void setDraft(Data::DraftKey key, std::unique_ptr<Data::Draft> &&draft);
|
||||||
|
@ -483,7 +471,6 @@ private:
|
||||||
|
|
||||||
enum class Flag : uchar {
|
enum class Flag : uchar {
|
||||||
HasPendingResizedItems = (1 << 0),
|
HasPendingResizedItems = (1 << 0),
|
||||||
UnreadThingsKnown = (1 << 1),
|
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) {
|
friend inline constexpr auto is_flag_type(Flag) {
|
||||||
|
@ -618,7 +605,6 @@ private:
|
||||||
std::optional<HistoryItem*> _lastServerMessage;
|
std::optional<HistoryItem*> _lastServerMessage;
|
||||||
base::flat_set<not_null<HistoryItem*>> _clientSideMessages;
|
base::flat_set<not_null<HistoryItem*>> _clientSideMessages;
|
||||||
std::unordered_set<std::unique_ptr<HistoryItem>> _messages;
|
std::unordered_set<std::unique_ptr<HistoryItem>> _messages;
|
||||||
std::unique_ptr<HistoryUnreadThings::All> _unreadThings;
|
|
||||||
|
|
||||||
// This almost always is equal to _lastMessage. The only difference is
|
// This almost always is equal to _lastMessage. The only difference is
|
||||||
// for a group that migrated to a supergroup. Then _lastMessage can
|
// for a group that migrated to a supergroup. Then _lastMessage can
|
||||||
|
|
|
@ -375,10 +375,8 @@ void HistoryItem::invalidateChatListEntry() {
|
||||||
this,
|
this,
|
||||||
Data::MessageUpdate::Flag::DialogRowRefresh);
|
Data::MessageUpdate::Flag::DialogRowRefresh);
|
||||||
history()->lastItemDialogsView.itemInvalidated(this);
|
history()->lastItemDialogsView.itemInvalidated(this);
|
||||||
if (const auto forum = history()->peer->forum()) {
|
if (const auto topic = this->topic()) {
|
||||||
if (const auto topic = forum->topicFor(this)) {
|
topic->lastItemDialogsView.itemInvalidated(this);
|
||||||
topic->lastItemDialogsView.itemInvalidated(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,8 +440,12 @@ void HistoryItem::markMediaAndMentionRead() {
|
||||||
_flags &= ~MessageFlag::MediaIsUnread;
|
_flags &= ~MessageFlag::MediaIsUnread;
|
||||||
|
|
||||||
if (mentionsMe()) {
|
if (mentionsMe()) {
|
||||||
history()->updateChatListEntry();
|
_history->updateChatListEntry();
|
||||||
history()->unreadMentions().erase(id);
|
_history->unreadMentions().erase(id);
|
||||||
|
if (const auto topic = this->topic()) {
|
||||||
|
topic->updateChatListEntry();
|
||||||
|
topic->unreadMentions().erase(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,8 +454,12 @@ void HistoryItem::markReactionsRead() {
|
||||||
_reactions->markRead();
|
_reactions->markRead();
|
||||||
}
|
}
|
||||||
_flags &= ~MessageFlag::HasUnreadReaction;
|
_flags &= ~MessageFlag::HasUnreadReaction;
|
||||||
history()->updateChatListEntry();
|
_history->updateChatListEntry();
|
||||||
history()->unreadReactions().erase(id);
|
_history->unreadReactions().erase(id);
|
||||||
|
if (const auto topic = this->topic()) {
|
||||||
|
topic->updateChatListEntry();
|
||||||
|
topic->unreadReactions().erase(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryItem::markContentsRead(bool fromThisClient) {
|
bool HistoryItem::markContentsRead(bool fromThisClient) {
|
||||||
|
@ -613,6 +619,11 @@ void HistoryItem::destroy() {
|
||||||
_history->destroyMessage(this);
|
_history->destroyMessage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data::ForumTopic *HistoryItem::topic() const {
|
||||||
|
const auto forum = _history->peer->forum();
|
||||||
|
return forum ? forum->topicFor(this) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryItem::refreshMainView() {
|
void HistoryItem::refreshMainView() {
|
||||||
if (const auto view = mainView()) {
|
if (const auto view = mainView()) {
|
||||||
_history->owner().notifyHistoryChangeDelayed(_history);
|
_history->owner().notifyHistoryChangeDelayed(_history);
|
||||||
|
|
|
@ -46,6 +46,7 @@ struct ReactionId;
|
||||||
class Media;
|
class Media;
|
||||||
struct MessageReaction;
|
struct MessageReaction;
|
||||||
class MessageReactions;
|
class MessageReactions;
|
||||||
|
class ForumTopic;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
|
@ -122,13 +123,14 @@ public:
|
||||||
const QString &label,
|
const QString &label,
|
||||||
const TextWithEntities &content);
|
const TextWithEntities &content);
|
||||||
|
|
||||||
not_null<History*> history() const {
|
[[nodiscard]] not_null<History*> history() const {
|
||||||
return _history;
|
return _history;
|
||||||
}
|
}
|
||||||
not_null<PeerData*> from() const {
|
[[nodiscard]] Data::ForumTopic *topic() const;
|
||||||
|
[[nodiscard]] not_null<PeerData*> from() const {
|
||||||
return _from;
|
return _from;
|
||||||
}
|
}
|
||||||
HistoryView::Element *mainView() const {
|
[[nodiscard]] HistoryView::Element *mainView() const {
|
||||||
return _mainView;
|
return _mainView;
|
||||||
}
|
}
|
||||||
void setMainView(not_null<HistoryView::Element*> view) {
|
void setMainView(not_null<HistoryView::Element*> view) {
|
||||||
|
|
|
@ -1331,24 +1331,46 @@ void HistoryMessage::addToUnreadThings(HistoryUnreadThings::AddType type) {
|
||||||
if (!isRegular()) {
|
if (!isRegular()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isUnreadMention()) {
|
const auto mention = isUnreadMention();
|
||||||
if (history()->unreadMentions().add(id, type)) {
|
const auto reaction = hasUnreadReaction();
|
||||||
history()->session().changes().historyUpdated(
|
if (!mention && !reaction) {
|
||||||
history(),
|
return;
|
||||||
|
}
|
||||||
|
const auto topic = this->topic();
|
||||||
|
const auto history = this->history();
|
||||||
|
const auto changes = &history->session().changes();
|
||||||
|
if (mention) {
|
||||||
|
if (history->unreadMentions().add(id, type)) {
|
||||||
|
changes->historyUpdated(
|
||||||
|
history,
|
||||||
Data::HistoryUpdate::Flag::UnreadMentions);
|
Data::HistoryUpdate::Flag::UnreadMentions);
|
||||||
}
|
}
|
||||||
|
if (topic && topic->unreadMentions().add(id, type)) {
|
||||||
|
changes->topicUpdated(
|
||||||
|
topic,
|
||||||
|
Data::TopicUpdate::Flag::UnreadMentions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hasUnreadReaction()) {
|
if (reaction) {
|
||||||
if (history()->unreadReactions().add(id, type)) {
|
const auto toHistory = history->unreadReactions().add(id, type);
|
||||||
|
const auto toTopic = topic && topic->unreadReactions().add(id, type);
|
||||||
|
if (toHistory || toTopic) {
|
||||||
if (type == HistoryUnreadThings::AddType::New) {
|
if (type == HistoryUnreadThings::AddType::New) {
|
||||||
history()->session().changes().messageUpdated(
|
changes->messageUpdated(
|
||||||
this,
|
this,
|
||||||
Data::MessageUpdate::Flag::NewUnreadReaction);
|
Data::MessageUpdate::Flag::NewUnreadReaction);
|
||||||
}
|
}
|
||||||
if (hasUnreadReaction()) {
|
if (hasUnreadReaction()) {
|
||||||
history()->session().changes().historyUpdated(
|
if (toHistory) {
|
||||||
history(),
|
changes->historyUpdated(
|
||||||
Data::HistoryUpdate::Flag::UnreadReactions);
|
history,
|
||||||
|
Data::HistoryUpdate::Flag::UnreadReactions);
|
||||||
|
}
|
||||||
|
if (toTopic) {
|
||||||
|
changes->topicUpdated(
|
||||||
|
topic,
|
||||||
|
Data::TopicUpdate::Flag::UnreadReactions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1357,9 +1379,15 @@ void HistoryMessage::addToUnreadThings(HistoryUnreadThings::AddType type) {
|
||||||
void HistoryMessage::destroyHistoryEntry() {
|
void HistoryMessage::destroyHistoryEntry() {
|
||||||
if (isUnreadMention()) {
|
if (isUnreadMention()) {
|
||||||
history()->unreadMentions().erase(id);
|
history()->unreadMentions().erase(id);
|
||||||
|
if (const auto topic = this->topic()) {
|
||||||
|
topic->unreadMentions().erase(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hasUnreadReaction()) {
|
if (hasUnreadReaction()) {
|
||||||
history()->unreadReactions().erase(id);
|
history()->unreadReactions().erase(id);
|
||||||
|
if (const auto topic = this->topic()) {
|
||||||
|
topic->unreadReactions().erase(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||||
changeReplyToTopCounter(reply, -1);
|
changeReplyToTopCounter(reply, -1);
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_chat_filters.h"
|
#include "data/data_chat_filters.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
@ -19,20 +20,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace HistoryUnreadThings {
|
namespace HistoryUnreadThings {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[nodiscard]] Data::HistoryUpdate::Flag UpdateFlag(Type type) {
|
template <typename Update>
|
||||||
using Flag = Data::HistoryUpdate::Flag;
|
[[nodiscard]] typename Update::Flag UpdateFlag(Type type) {
|
||||||
|
using Flag = typename Update::Flag;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::Mentions: return Flag::UnreadMentions;
|
case Type::Mentions: return Flag::UnreadMentions;
|
||||||
case Type::Reactions: return Flag::UnreadReactions;
|
case Type::Reactions: return Flag::UnreadReactions;
|
||||||
}
|
}
|
||||||
Unexpected("Type in Proxy::addSlice.");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Proxy::setCount(int count) {
|
void Proxy::setCount(int count) {
|
||||||
if (!_known) {
|
if (!_known) {
|
||||||
_history->setUnreadThingsKnown();
|
_entry->setUnreadThingsKnown();
|
||||||
}
|
}
|
||||||
if (!_data) {
|
if (!_data) {
|
||||||
if (!count) {
|
if (!count) {
|
||||||
|
@ -59,16 +69,19 @@ void Proxy::setCount(int count) {
|
||||||
const auto has = (count > 0);
|
const auto has = (count > 0);
|
||||||
if (has != had) {
|
if (has != had) {
|
||||||
if (_type == Type::Mentions) {
|
if (_type == Type::Mentions) {
|
||||||
_history->owner().chatsFilters().refreshHistory(_history);
|
if (const auto history = _entry->asHistory()) {
|
||||||
|
_entry->owner().chatsFilters().refreshHistory(history);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_history->updateChatListEntry();
|
_entry->updateChatListEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Proxy::add(MsgId msgId, AddType type) {
|
bool Proxy::add(MsgId msgId, AddType type) {
|
||||||
const auto peer = _history->peer;
|
if (const auto history = _entry->asHistory()) {
|
||||||
if (peer->isChannel() && !peer->isMegagroup()) {
|
if (history->peer->isBroadcast()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_data) {
|
if (!_data) {
|
||||||
|
@ -89,7 +102,6 @@ bool Proxy::add(MsgId msgId, AddType type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Proxy::erase(MsgId msgId) {
|
void Proxy::erase(MsgId msgId) {
|
||||||
|
@ -101,9 +113,7 @@ void Proxy::erase(MsgId msgId) {
|
||||||
if (const auto count = list.count(); count > 0) {
|
if (const auto count = list.count(); count > 0) {
|
||||||
setCount(count - 1);
|
setCount(count - 1);
|
||||||
}
|
}
|
||||||
_history->session().changes().historyUpdated(
|
notifyUpdated();
|
||||||
_history,
|
|
||||||
UpdateFlag(_type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Proxy::clear() {
|
void Proxy::clear() {
|
||||||
|
@ -113,15 +123,14 @@ void Proxy::clear() {
|
||||||
auto &list = resolveList();
|
auto &list = resolveList();
|
||||||
list.clear();
|
list.clear();
|
||||||
setCount(0);
|
setCount(0);
|
||||||
_history->session().changes().historyUpdated(
|
notifyUpdated();
|
||||||
_history,
|
|
||||||
UpdateFlag(_type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
||||||
if (!alreadyLoaded && _data) {
|
if (!alreadyLoaded && _data) {
|
||||||
resolveList().clear();
|
resolveList().clear();
|
||||||
}
|
}
|
||||||
|
const auto history = resolveHistory();
|
||||||
auto fullCount = slice.match([&](
|
auto fullCount = slice.match([&](
|
||||||
const MTPDmessages_messagesNotModified &) {
|
const MTPDmessages_messagesNotModified &) {
|
||||||
LOG(("API Error: received messages.messagesNotModified! "
|
LOG(("API Error: received messages.messagesNotModified! "
|
||||||
|
@ -132,8 +141,8 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
||||||
}, [&](const MTPDmessages_messagesSlice &data) {
|
}, [&](const MTPDmessages_messagesSlice &data) {
|
||||||
return data.vcount().v;
|
return data.vcount().v;
|
||||||
}, [&](const MTPDmessages_channelMessages &data) {
|
}, [&](const MTPDmessages_channelMessages &data) {
|
||||||
if (_history->peer->isChannel()) {
|
if (const auto channel = history->peer->asChannel()) {
|
||||||
_history->peer->asChannel()->ptsReceived(data.vpts().v);
|
channel->ptsReceived(data.vpts().v);
|
||||||
} else {
|
} else {
|
||||||
LOG(("API Error: received messages.channelMessages when "
|
LOG(("API Error: received messages.channelMessages when "
|
||||||
"no channel was passed! (Proxy::addSlice)"));
|
"no channel was passed! (Proxy::addSlice)"));
|
||||||
|
@ -141,7 +150,7 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
||||||
return data.vcount().v;
|
return data.vcount().v;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto &owner = _history->owner();
|
auto &owner = _entry->owner();
|
||||||
const auto messages = slice.match([&](
|
const auto messages = slice.match([&](
|
||||||
const MTPDmessages_messagesNotModified &) {
|
const MTPDmessages_messagesNotModified &) {
|
||||||
LOG(("API Error: received messages.messagesNotModified! "
|
LOG(("API Error: received messages.messagesNotModified! "
|
||||||
|
@ -160,7 +169,7 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
||||||
const auto localFlags = MessageFlags();
|
const auto localFlags = MessageFlags();
|
||||||
const auto type = NewMessageType::Existing;
|
const auto type = NewMessageType::Existing;
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
const auto item = _history->addNewMessage(
|
const auto item = history->addNewMessage(
|
||||||
IdFromMessage(message),
|
IdFromMessage(message),
|
||||||
message,
|
message,
|
||||||
localFlags,
|
localFlags,
|
||||||
|
@ -181,9 +190,7 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
|
||||||
fullCount = loadedCount();
|
fullCount = loadedCount();
|
||||||
}
|
}
|
||||||
setCount(fullCount);
|
setCount(fullCount);
|
||||||
_history->session().changes().historyUpdated(
|
notifyUpdated();
|
||||||
_history,
|
|
||||||
UpdateFlag(_type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Proxy::checkAdd(MsgId msgId, bool resolved) {
|
void Proxy::checkAdd(MsgId msgId, bool resolved) {
|
||||||
|
@ -196,7 +203,7 @@ void Proxy::checkAdd(MsgId msgId, bool resolved) {
|
||||||
if (!list.loadedCount() || list.maxLoaded() <= msgId) {
|
if (!list.loadedCount() || list.maxLoaded() <= msgId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto history = _history;
|
const auto history = resolveHistory();
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
const auto item = peer->owner().message(peer, msgId);
|
const auto item = peer->owner().message(peer, msgId);
|
||||||
if (item && item->hasUnreadReaction()) {
|
if (item && item->hasUnreadReaction()) {
|
||||||
|
@ -208,6 +215,18 @@ void Proxy::checkAdd(MsgId msgId, bool resolved) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Proxy::notifyUpdated() {
|
||||||
|
if (const auto history = _entry->asHistory()) {
|
||||||
|
history->session().changes().historyUpdated(
|
||||||
|
history,
|
||||||
|
HistoryUpdateFlag(_type));
|
||||||
|
} else if (const auto topic = _entry->asTopic()) {
|
||||||
|
topic->session().changes().topicUpdated(
|
||||||
|
topic,
|
||||||
|
TopicUpdateFlag(_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Proxy::createData() {
|
void Proxy::createData() {
|
||||||
_data = std::make_unique<All>();
|
_data = std::make_unique<All>();
|
||||||
if (_known) {
|
if (_known) {
|
||||||
|
@ -216,7 +235,7 @@ void Proxy::createData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] List &Proxy::resolveList() {
|
List &Proxy::resolveList() {
|
||||||
Expects(_data != nullptr);
|
Expects(_data != nullptr);
|
||||||
|
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
|
@ -226,4 +245,9 @@ void Proxy::createData() {
|
||||||
Unexpected("Unread things type in Proxy::resolveList.");
|
Unexpected("Unread things type in Proxy::resolveList.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<History*> Proxy::resolveHistory() const {
|
||||||
|
const auto result = _entry->asHistory();
|
||||||
|
return result ? not_null(result) : _entry->asTopic()->history();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace HistoryUnreadThings
|
} // namespace HistoryUnreadThings
|
||||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Entry;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace HistoryUnreadThings {
|
namespace HistoryUnreadThings {
|
||||||
|
|
||||||
enum class AddType {
|
enum class AddType {
|
||||||
|
@ -41,6 +45,9 @@ public:
|
||||||
[[nodiscard]] bool contains(MsgId msgId) const {
|
[[nodiscard]] bool contains(MsgId msgId) const {
|
||||||
return _messages.contains(msgId);
|
return _messages.contains(msgId);
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] const base::flat_set<MsgId> &ids() const {
|
||||||
|
return _messages;
|
||||||
|
}
|
||||||
void setCount(int count) {
|
void setCount(int count) {
|
||||||
_count = count;
|
_count = count;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +108,7 @@ private:
|
||||||
class Proxy final : public ConstProxy {
|
class Proxy final : public ConstProxy {
|
||||||
public:
|
public:
|
||||||
Proxy(
|
Proxy(
|
||||||
not_null<History*> history,
|
not_null<Dialogs::Entry*> entry,
|
||||||
std::unique_ptr<All> &data,
|
std::unique_ptr<All> &data,
|
||||||
Type type,
|
Type type,
|
||||||
bool known)
|
bool known)
|
||||||
|
@ -112,7 +119,7 @@ public:
|
||||||
? &data->mentions
|
? &data->mentions
|
||||||
: &data->reactions),
|
: &data->reactions),
|
||||||
known)
|
known)
|
||||||
, _history(history)
|
, _entry(entry)
|
||||||
, _data(data)
|
, _data(data)
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _known(known) {
|
, _known(known) {
|
||||||
|
@ -129,9 +136,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createData();
|
void createData();
|
||||||
|
void notifyUpdated();
|
||||||
[[nodiscard]] List &resolveList();
|
[[nodiscard]] List &resolveList();
|
||||||
|
[[nodiscard]] not_null<History*> resolveHistory() const;
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<Dialogs::Entry*> _entry;
|
||||||
std::unique_ptr<All> &_data;
|
std::unique_ptr<All> &_data;
|
||||||
Type _type = Type::Mentions;
|
Type _type = Type::Mentions;
|
||||||
bool _known = false;
|
bool _known = false;
|
||||||
|
|
|
@ -390,7 +390,7 @@ HistoryWidget::HistoryWidget(
|
||||||
_unreadReactions.widget->installEventFilter(this);
|
_unreadReactions.widget->installEventFilter(this);
|
||||||
SendMenu::SetupUnreadMentionsMenu(_unreadMentions.widget.data(), [=] {
|
SendMenu::SetupUnreadMentionsMenu(_unreadMentions.widget.data(), [=] {
|
||||||
return _history ? _history->peer.get() : nullptr;
|
return _history ? _history->peer.get() : nullptr;
|
||||||
});
|
}, MsgId(0));
|
||||||
SendMenu::SetupUnreadReactionsMenu(_unreadReactions.widget.data(), [=] {
|
SendMenu::SetupUnreadReactionsMenu(_unreadReactions.widget.data(), [=] {
|
||||||
return _history ? _history->peer.get() : nullptr;
|
return _history ? _history->peer.get() : nullptr;
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_forum.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -186,18 +188,33 @@ void SetupReadAllMenu(
|
||||||
|
|
||||||
void SetupUnreadMentionsMenu(
|
void SetupUnreadMentionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer) {
|
Fn<PeerData*()> currentPeer,
|
||||||
const auto topMsgId = 0;
|
MsgId topicRootId) {
|
||||||
const auto text = tr::lng_context_mark_read_mentions_all(tr::now);
|
const auto text = tr::lng_context_mark_read_mentions_all(tr::now);
|
||||||
const auto sendRequest = [=](not_null<PeerData*> peer, Fn<void()> done) {
|
const auto sendRequest = [=](not_null<PeerData*> peer, Fn<void()> done) {
|
||||||
|
using Flag = MTPmessages_ReadMentions::Flag;
|
||||||
peer->session().api().request(MTPmessages_ReadMentions(
|
peer->session().api().request(MTPmessages_ReadMentions(
|
||||||
MTP_flags(0),
|
MTP_flags(topicRootId ? Flag::f_top_msg_id : Flag()),
|
||||||
peer->input,
|
peer->input,
|
||||||
MTP_int(topMsgId)
|
MTP_int(topicRootId)
|
||||||
)).done([=](const MTPmessages_AffectedHistory &result) {
|
)).done([=](const MTPmessages_AffectedHistory &result) {
|
||||||
done();
|
done();
|
||||||
peer->session().api().applyAffectedHistory(peer, result);
|
peer->session().api().applyAffectedHistory(peer, result);
|
||||||
peer->owner().history(peer)->unreadMentions().clear();
|
const auto forum = peer->forum();
|
||||||
|
const auto history = peer->owner().history(peer);
|
||||||
|
if (!topicRootId) {
|
||||||
|
history->unreadMentions().clear();
|
||||||
|
if (forum) {
|
||||||
|
forum->clearAllUnreadMentions();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (forum) {
|
||||||
|
if (const auto topic = forum->topicFor(topicRootId)) {
|
||||||
|
topic->unreadMentions().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
history->clearUnreadMentionsFor(topicRootId);
|
||||||
|
}
|
||||||
}).fail(done).send();
|
}).fail(done).send();
|
||||||
};
|
};
|
||||||
SetupReadAllMenu(button, currentPeer, text, sendRequest);
|
SetupReadAllMenu(button, currentPeer, text, sendRequest);
|
||||||
|
|
|
@ -51,7 +51,8 @@ void SetupMenuAndShortcuts(
|
||||||
|
|
||||||
void SetupUnreadMentionsMenu(
|
void SetupUnreadMentionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer);
|
Fn<PeerData*()> currentPeer,
|
||||||
|
MsgId topicRootId);
|
||||||
|
|
||||||
void SetupUnreadReactionsMenu(
|
void SetupUnreadReactionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
|
|
Loading…
Add table
Reference in a new issue