395 lines
11 KiB
C++
395 lines
11 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#pragma once
|
|
|
|
#include "base/flags.h"
|
|
|
|
class History;
|
|
class PeerData;
|
|
class HistoryItem;
|
|
|
|
namespace Dialogs {
|
|
class Entry;
|
|
} // namespace Dialogs
|
|
|
|
namespace Main {
|
|
class Session;
|
|
} // namespace Main
|
|
|
|
namespace Data::details {
|
|
|
|
template <typename Flag>
|
|
inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) {
|
|
auto i = 0;
|
|
while ((1ULL << i) != static_cast<uint64>(Last)) {
|
|
++i;
|
|
Assert(i != 64);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
} // namespace Data::details
|
|
|
|
namespace Data {
|
|
|
|
class ForumTopic;
|
|
class Story;
|
|
|
|
struct NameUpdate {
|
|
NameUpdate(
|
|
not_null<PeerData*> peer,
|
|
base::flat_set<QChar> oldFirstLetters)
|
|
: peer(peer)
|
|
, oldFirstLetters(std::move(oldFirstLetters)) {
|
|
}
|
|
|
|
not_null<PeerData*> peer;
|
|
base::flat_set<QChar> oldFirstLetters;
|
|
};
|
|
|
|
struct PeerUpdate {
|
|
enum class Flag : uint64 {
|
|
None = 0,
|
|
|
|
// Common flags
|
|
Name = (1ULL << 0),
|
|
Username = (1ULL << 1),
|
|
Photo = (1ULL << 2),
|
|
About = (1ULL << 3),
|
|
Notifications = (1ULL << 4),
|
|
Migration = (1ULL << 5),
|
|
UnavailableReason = (1ULL << 6),
|
|
ChatThemeEmoji = (1ULL << 7),
|
|
ChatWallPaper = (1ULL << 8),
|
|
IsBlocked = (1ULL << 9),
|
|
MessagesTTL = (1ULL << 10),
|
|
FullInfo = (1ULL << 11),
|
|
Usernames = (1ULL << 12),
|
|
TranslationDisabled = (1ULL << 13),
|
|
|
|
// For users
|
|
CanShareContact = (1ULL << 14),
|
|
IsContact = (1ULL << 15),
|
|
PhoneNumber = (1ULL << 16),
|
|
OnlineStatus = (1ULL << 17),
|
|
BotCommands = (1ULL << 18),
|
|
BotCanBeInvited = (1ULL << 19),
|
|
BotStartToken = (1ULL << 20),
|
|
CommonChats = (1ULL << 21),
|
|
HasCalls = (1ULL << 22),
|
|
SupportInfo = (1ULL << 23),
|
|
IsBot = (1ULL << 24),
|
|
EmojiStatus = (1ULL << 25),
|
|
StoriesState = (1ULL << 26),
|
|
|
|
// For chats and channels
|
|
InviteLinks = (1ULL << 27),
|
|
Members = (1ULL << 28),
|
|
Admins = (1ULL << 29),
|
|
BannedUsers = (1ULL << 30),
|
|
Rights = (1ULL << 31),
|
|
PendingRequests = (1ULL << 32),
|
|
Reactions = (1ULL << 33),
|
|
|
|
// For channels
|
|
ChannelAmIn = (1ULL << 34),
|
|
StickersSet = (1ULL << 35),
|
|
ChannelLinkedChat = (1ULL << 36),
|
|
ChannelLocation = (1ULL << 37),
|
|
Slowmode = (1ULL << 38),
|
|
GroupCall = (1ULL << 39),
|
|
|
|
// For iteration
|
|
LastUsedBit = (1ULL << 39),
|
|
};
|
|
using Flags = base::flags<Flag>;
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
not_null<PeerData*> peer;
|
|
Flags flags = 0;
|
|
|
|
};
|
|
|
|
struct HistoryUpdate {
|
|
enum class Flag : uint32 {
|
|
None = 0,
|
|
|
|
IsPinned = (1U << 0),
|
|
UnreadView = (1U << 1),
|
|
TopPromoted = (1U << 2),
|
|
Folder = (1U << 3),
|
|
UnreadMentions = (1U << 4),
|
|
UnreadReactions = (1U << 5),
|
|
ClientSideMessages = (1U << 6),
|
|
ChatOccupied = (1U << 7),
|
|
MessageSent = (1U << 8),
|
|
ScheduledSent = (1U << 9),
|
|
OutboxRead = (1U << 10),
|
|
BotKeyboard = (1U << 11),
|
|
CloudDraft = (1U << 12),
|
|
TranslateFrom = (1U << 13),
|
|
TranslatedTo = (1U << 14),
|
|
|
|
LastUsedBit = (1U << 14),
|
|
};
|
|
using Flags = base::flags<Flag>;
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
not_null<History*> history;
|
|
Flags flags = 0;
|
|
|
|
};
|
|
|
|
struct TopicUpdate {
|
|
enum class Flag : uint32 {
|
|
None = 0,
|
|
|
|
UnreadView = (1U << 1),
|
|
UnreadMentions = (1U << 2),
|
|
UnreadReactions = (1U << 3),
|
|
Notifications = (1U << 4),
|
|
Title = (1U << 5),
|
|
IconId = (1U << 6),
|
|
ColorId = (1U << 7),
|
|
CloudDraft = (1U << 8),
|
|
Closed = (1U << 9),
|
|
Creator = (1U << 10),
|
|
Destroyed = (1U << 11),
|
|
|
|
LastUsedBit = (1U << 11),
|
|
};
|
|
using Flags = base::flags<Flag>;
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
not_null<ForumTopic*> topic;
|
|
Flags flags = 0;
|
|
|
|
};
|
|
|
|
struct MessageUpdate {
|
|
enum class Flag : uint32 {
|
|
None = 0,
|
|
|
|
Edited = (1U << 0),
|
|
Destroyed = (1U << 1),
|
|
DialogRowRepaint = (1U << 2),
|
|
DialogRowRefresh = (1U << 3),
|
|
NewAdded = (1U << 4),
|
|
ReplyMarkup = (1U << 5),
|
|
BotCallbackSent = (1U << 6),
|
|
NewMaybeAdded = (1U << 7),
|
|
ReplyToTopAdded = (1U << 8),
|
|
NewUnreadReaction = (1U << 9),
|
|
|
|
LastUsedBit = (1U << 9),
|
|
};
|
|
using Flags = base::flags<Flag>;
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
not_null<HistoryItem*> item;
|
|
Flags flags = 0;
|
|
|
|
};
|
|
|
|
struct EntryUpdate {
|
|
enum class Flag : uint32 {
|
|
None = 0,
|
|
|
|
Repaint = (1U << 0),
|
|
HasPinnedMessages = (1U << 1),
|
|
ForwardDraft = (1U << 2),
|
|
LocalDraftSet = (1U << 3),
|
|
Height = (1U << 4),
|
|
Destroyed = (1U << 5),
|
|
|
|
LastUsedBit = (1U << 5),
|
|
};
|
|
using Flags = base::flags<Flag>;
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
not_null<Dialogs::Entry*> entry;
|
|
Flags flags = 0;
|
|
|
|
};
|
|
|
|
struct StoryUpdate {
|
|
enum class Flag : uint32 {
|
|
None = 0,
|
|
|
|
Edited = (1U << 0),
|
|
Destroyed = (1U << 1),
|
|
NewAdded = (1U << 2),
|
|
ViewsAdded = (1U << 3),
|
|
MarkRead = (1U << 4),
|
|
Reaction = (1U << 5),
|
|
|
|
LastUsedBit = (1U << 5),
|
|
};
|
|
using Flags = base::flags<Flag>;
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
not_null<Story*> story;
|
|
Flags flags = 0;
|
|
|
|
};
|
|
|
|
class Changes final {
|
|
public:
|
|
explicit Changes(not_null<Main::Session*> session);
|
|
|
|
[[nodiscard]] Main::Session &session() const;
|
|
|
|
void nameUpdated(
|
|
not_null<PeerData*> peer,
|
|
base::flat_set<QChar> oldFirstLetters);
|
|
[[nodiscard]] rpl::producer<NameUpdate> realtimeNameUpdates() const;
|
|
[[nodiscard]] rpl::producer<NameUpdate> realtimeNameUpdates(
|
|
not_null<PeerData*> peer) const;
|
|
|
|
void peerUpdated(not_null<PeerData*> peer, PeerUpdate::Flags flags);
|
|
[[nodiscard]] rpl::producer<PeerUpdate> peerUpdates(
|
|
PeerUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<PeerUpdate> peerUpdates(
|
|
not_null<PeerData*> peer,
|
|
PeerUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<PeerUpdate> peerFlagsValue(
|
|
not_null<PeerData*> peer,
|
|
PeerUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<PeerUpdate> realtimePeerUpdates(
|
|
PeerUpdate::Flag flag) const;
|
|
|
|
void historyUpdated(
|
|
not_null<History*> history,
|
|
HistoryUpdate::Flags flags);
|
|
[[nodiscard]] rpl::producer<HistoryUpdate> historyUpdates(
|
|
HistoryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<HistoryUpdate> historyUpdates(
|
|
not_null<History*> history,
|
|
HistoryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<HistoryUpdate> historyFlagsValue(
|
|
not_null<History*> history,
|
|
HistoryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<HistoryUpdate> realtimeHistoryUpdates(
|
|
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 topicRemoved(not_null<ForumTopic*> topic);
|
|
|
|
void messageUpdated(
|
|
not_null<HistoryItem*> item,
|
|
MessageUpdate::Flags flags);
|
|
[[nodiscard]] rpl::producer<MessageUpdate> messageUpdates(
|
|
MessageUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<MessageUpdate> messageUpdates(
|
|
not_null<HistoryItem*> item,
|
|
MessageUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<MessageUpdate> messageFlagsValue(
|
|
not_null<HistoryItem*> item,
|
|
MessageUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<MessageUpdate> realtimeMessageUpdates(
|
|
MessageUpdate::Flag flag) const;
|
|
|
|
void entryUpdated(
|
|
not_null<Dialogs::Entry*> entry,
|
|
EntryUpdate::Flags flags);
|
|
[[nodiscard]] rpl::producer<EntryUpdate> entryUpdates(
|
|
EntryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<EntryUpdate> entryUpdates(
|
|
not_null<Dialogs::Entry*> entry,
|
|
EntryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<EntryUpdate> entryFlagsValue(
|
|
not_null<Dialogs::Entry*> entry,
|
|
EntryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<EntryUpdate> realtimeEntryUpdates(
|
|
EntryUpdate::Flag flag) const;
|
|
void entryRemoved(not_null<Dialogs::Entry*> entry);
|
|
|
|
void storyUpdated(
|
|
not_null<Story*> story,
|
|
StoryUpdate::Flags flags);
|
|
[[nodiscard]] rpl::producer<StoryUpdate> storyUpdates(
|
|
StoryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<StoryUpdate> storyUpdates(
|
|
not_null<Story*> story,
|
|
StoryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<StoryUpdate> storyFlagsValue(
|
|
not_null<Story*> story,
|
|
StoryUpdate::Flags flags) const;
|
|
[[nodiscard]] rpl::producer<StoryUpdate> realtimeStoryUpdates(
|
|
StoryUpdate::Flag flag) const;
|
|
|
|
void sendNotifications();
|
|
|
|
private:
|
|
template <typename DataType, typename UpdateType>
|
|
class Manager final {
|
|
public:
|
|
using Flag = typename UpdateType::Flag;
|
|
using Flags = typename UpdateType::Flags;
|
|
|
|
void updated(
|
|
not_null<DataType*> data,
|
|
Flags flags,
|
|
bool dropScheduled = false);
|
|
[[nodiscard]] rpl::producer<UpdateType> updates(Flags flags) const;
|
|
[[nodiscard]] rpl::producer<UpdateType> updates(
|
|
not_null<DataType*> data,
|
|
Flags flags) const;
|
|
[[nodiscard]] rpl::producer<UpdateType> flagsValue(
|
|
not_null<DataType*> data,
|
|
Flags flags) const;
|
|
[[nodiscard]] rpl::producer<UpdateType> realtimeUpdates(
|
|
Flag flag) const;
|
|
|
|
void drop(not_null<DataType*> data);
|
|
|
|
void sendNotifications();
|
|
|
|
private:
|
|
static constexpr auto kCount = details::CountBit<Flag>() + 1;
|
|
|
|
void sendRealtimeNotifications(
|
|
not_null<DataType*> data,
|
|
Flags flags);
|
|
|
|
std::array<rpl::event_stream<UpdateType>, kCount> _realtimeStreams;
|
|
base::flat_map<not_null<DataType*>, Flags> _updates;
|
|
rpl::event_stream<UpdateType> _stream;
|
|
|
|
};
|
|
|
|
void scheduleNotifications();
|
|
|
|
const not_null<Main::Session*> _session;
|
|
|
|
rpl::event_stream<NameUpdate> _nameStream;
|
|
Manager<PeerData, PeerUpdate> _peerChanges;
|
|
Manager<History, HistoryUpdate> _historyChanges;
|
|
Manager<ForumTopic, TopicUpdate> _topicChanges;
|
|
Manager<HistoryItem, MessageUpdate> _messageChanges;
|
|
Manager<Dialogs::Entry, EntryUpdate> _entryChanges;
|
|
Manager<Story, StoryUpdate> _storyChanges;
|
|
|
|
bool _notify = false;
|
|
|
|
};
|
|
|
|
} // namespace Data
|