/* 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 inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) { auto i = 0; while ((1ULL << i) != static_cast(Last)) { ++i; Assert(i != 64); } return i; } } // namespace Data::details namespace Data { class ForumTopic; class Story; struct NameUpdate { NameUpdate( not_null peer, base::flat_set oldFirstLetters) : peer(peer) , oldFirstLetters(std::move(oldFirstLetters)) { } not_null peer; base::flat_set 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), Color = (1ULL << 14), BackgroundEmoji = (1ULL << 15), StoriesState = (1ULL << 16), // For users CanShareContact = (1ULL << 17), IsContact = (1ULL << 18), PhoneNumber = (1ULL << 19), OnlineStatus = (1ULL << 20), BotCommands = (1ULL << 21), BotCanBeInvited = (1ULL << 22), BotStartToken = (1ULL << 23), CommonChats = (1ULL << 24), HasCalls = (1ULL << 25), SupportInfo = (1ULL << 26), IsBot = (1ULL << 27), EmojiStatus = (1ULL << 28), BusinessDetails = (1ULL << 29), // For chats and channels InviteLinks = (1ULL << 30), Members = (1ULL << 31), Admins = (1ULL << 32), BannedUsers = (1ULL << 33), Rights = (1ULL << 34), PendingRequests = (1ULL << 35), Reactions = (1ULL << 36), // For channels ChannelAmIn = (1ULL << 37), StickersSet = (1ULL << 38), EmojiSet = (1ULL << 39), ChannelLinkedChat = (1ULL << 40), ChannelLocation = (1ULL << 41), Slowmode = (1ULL << 42), GroupCall = (1ULL << 43), // For iteration LastUsedBit = (1ULL << 43), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } not_null 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; friend inline constexpr auto is_flag_type(Flag) { return true; } not_null 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; friend inline constexpr auto is_flag_type(Flag) { return true; } not_null 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; friend inline constexpr auto is_flag_type(Flag) { return true; } not_null 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; friend inline constexpr auto is_flag_type(Flag) { return true; } not_null entry; Flags flags = 0; }; struct StoryUpdate { enum class Flag : uint32 { None = 0, Edited = (1U << 0), Destroyed = (1U << 1), NewAdded = (1U << 2), ViewsChanged = (1U << 3), MarkRead = (1U << 4), Reaction = (1U << 5), LastUsedBit = (1U << 5), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } not_null story; Flags flags = 0; }; class Changes final { public: explicit Changes(not_null session); [[nodiscard]] Main::Session &session() const; void nameUpdated( not_null peer, base::flat_set oldFirstLetters); [[nodiscard]] rpl::producer realtimeNameUpdates() const; [[nodiscard]] rpl::producer realtimeNameUpdates( not_null peer) const; void peerUpdated(not_null peer, PeerUpdate::Flags flags); [[nodiscard]] rpl::producer peerUpdates( PeerUpdate::Flags flags) const; [[nodiscard]] rpl::producer peerUpdates( not_null peer, PeerUpdate::Flags flags) const; [[nodiscard]] rpl::producer peerFlagsValue( not_null peer, PeerUpdate::Flags flags) const; [[nodiscard]] rpl::producer realtimePeerUpdates( PeerUpdate::Flag flag) const; void historyUpdated( not_null history, HistoryUpdate::Flags flags); [[nodiscard]] rpl::producer historyUpdates( HistoryUpdate::Flags flags) const; [[nodiscard]] rpl::producer historyUpdates( not_null history, HistoryUpdate::Flags flags) const; [[nodiscard]] rpl::producer historyFlagsValue( not_null history, HistoryUpdate::Flags flags) const; [[nodiscard]] rpl::producer realtimeHistoryUpdates( HistoryUpdate::Flag flag) const; void topicUpdated( not_null topic, TopicUpdate::Flags flags); [[nodiscard]] rpl::producer topicUpdates( TopicUpdate::Flags flags) const; [[nodiscard]] rpl::producer topicUpdates( not_null topic, TopicUpdate::Flags flags) const; [[nodiscard]] rpl::producer topicFlagsValue( not_null topic, TopicUpdate::Flags flags) const; [[nodiscard]] rpl::producer realtimeTopicUpdates( TopicUpdate::Flag flag) const; void topicRemoved(not_null topic); void messageUpdated( not_null item, MessageUpdate::Flags flags); [[nodiscard]] rpl::producer messageUpdates( MessageUpdate::Flags flags) const; [[nodiscard]] rpl::producer messageUpdates( not_null item, MessageUpdate::Flags flags) const; [[nodiscard]] rpl::producer messageFlagsValue( not_null item, MessageUpdate::Flags flags) const; [[nodiscard]] rpl::producer realtimeMessageUpdates( MessageUpdate::Flag flag) const; void entryUpdated( not_null entry, EntryUpdate::Flags flags); [[nodiscard]] rpl::producer entryUpdates( EntryUpdate::Flags flags) const; [[nodiscard]] rpl::producer entryUpdates( not_null entry, EntryUpdate::Flags flags) const; [[nodiscard]] rpl::producer entryFlagsValue( not_null entry, EntryUpdate::Flags flags) const; [[nodiscard]] rpl::producer realtimeEntryUpdates( EntryUpdate::Flag flag) const; void entryRemoved(not_null entry); void storyUpdated( not_null story, StoryUpdate::Flags flags); [[nodiscard]] rpl::producer storyUpdates( StoryUpdate::Flags flags) const; [[nodiscard]] rpl::producer storyUpdates( not_null story, StoryUpdate::Flags flags) const; [[nodiscard]] rpl::producer storyFlagsValue( not_null story, StoryUpdate::Flags flags) const; [[nodiscard]] rpl::producer realtimeStoryUpdates( StoryUpdate::Flag flag) const; void sendNotifications(); private: template class Manager final { public: using Flag = typename UpdateType::Flag; using Flags = typename UpdateType::Flags; void updated( not_null data, Flags flags, bool dropScheduled = false); [[nodiscard]] rpl::producer updates(Flags flags) const; [[nodiscard]] rpl::producer updates( not_null data, Flags flags) const; [[nodiscard]] rpl::producer flagsValue( not_null data, Flags flags) const; [[nodiscard]] rpl::producer realtimeUpdates( Flag flag) const; void drop(not_null data); void sendNotifications(); private: static constexpr auto kCount = details::CountBit() + 1; void sendRealtimeNotifications( not_null data, Flags flags); std::array, kCount> _realtimeStreams; base::flat_map, Flags> _updates; rpl::event_stream _stream; }; void scheduleNotifications(); const not_null _session; rpl::event_stream _nameStream; Manager _peerChanges; Manager _historyChanges; Manager _topicChanges; Manager _messageChanges; Manager _entryChanges; Manager _storyChanges; bool _notify = false; }; } // namespace Data