1 /* 2 This file is part of Telegram Desktop, 3 the official desktop application for the Telegram messaging service. 4 5 For license and copyright information please follow this link: 6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7 */ 8 #pragma once 9 10 #include "base/flags.h" 11 12 class History; 13 class PeerData; 14 class HistoryItem; 15 16 namespace Dialogs { 17 class Entry; 18 } // namespace Dialogs 19 20 namespace Main { 21 class Session; 22 } // namespace Main 23 24 namespace Data { 25 26 namespace details { 27 28 template <typename Flag> 29 inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) { 30 auto i = 0; 31 while ((1ULL << i) != static_cast<uint64>(Last)) { 32 ++i; 33 Assert(i != 64); 34 } 35 return (i + 1); 36 } 37 38 } // namespace details 39 40 struct NameUpdate { NameUpdateNameUpdate41 NameUpdate( 42 not_null<PeerData*> peer, 43 base::flat_set<QChar> oldFirstLetters) 44 : peer(peer) 45 , oldFirstLetters(std::move(oldFirstLetters)) { 46 } 47 48 not_null<PeerData*> peer; 49 base::flat_set<QChar> oldFirstLetters; 50 }; 51 52 struct PeerUpdate { 53 enum class Flag : uint64 { 54 None = 0, 55 56 // Common flags 57 Name = (1ULL << 0), 58 Username = (1ULL << 1), 59 Photo = (1ULL << 2), 60 About = (1ULL << 3), 61 Notifications = (1ULL << 4), 62 Migration = (1ULL << 5), 63 UnavailableReason = (1ULL << 6), 64 ChatThemeEmoji = (1ULL << 7), 65 IsBlocked = (1ULL << 8), 66 MessagesTTL = (1ULL << 9), 67 FullInfo = (1ULL << 10), 68 69 // For users 70 CanShareContact = (1ULL << 11), 71 IsContact = (1ULL << 12), 72 PhoneNumber = (1ULL << 13), 73 OnlineStatus = (1ULL << 14), 74 BotCommands = (1ULL << 15), 75 BotCanBeInvited = (1ULL << 16), 76 BotStartToken = (1ULL << 17), 77 CommonChats = (1ULL << 18), 78 HasCalls = (1ULL << 19), 79 SupportInfo = (1ULL << 20), 80 IsBot = (1ULL << 21), 81 82 // For chats and channels 83 InviteLinks = (1ULL << 22), 84 Members = (1ULL << 23), 85 Admins = (1ULL << 24), 86 BannedUsers = (1ULL << 25), 87 Rights = (1ULL << 26), 88 PendingRequests = (1ULL << 27), 89 90 // For channels 91 ChannelAmIn = (1ULL << 28), 92 StickersSet = (1ULL << 29), 93 ChannelLinkedChat = (1ULL << 30), 94 ChannelLocation = (1ULL << 31), 95 Slowmode = (1ULL << 32), 96 GroupCall = (1ULL << 33), 97 98 // For iteration 99 LastUsedBit = (1ULL << 33), 100 }; 101 using Flags = base::flags<Flag>; is_flag_typePeerUpdate102 friend inline constexpr auto is_flag_type(Flag) { return true; } 103 104 not_null<PeerData*> peer; 105 Flags flags = 0; 106 107 }; 108 109 struct HistoryUpdate { 110 enum class Flag : uint32 { 111 None = 0, 112 113 IsPinned = (1U << 0), 114 UnreadView = (1U << 1), 115 TopPromoted = (1U << 2), 116 Folder = (1U << 3), 117 UnreadMentions = (1U << 4), 118 ClientSideMessages = (1U << 5), 119 ChatOccupied = (1U << 6), 120 MessageSent = (1U << 7), 121 ScheduledSent = (1U << 8), 122 ForwardDraft = (1U << 9), 123 OutboxRead = (1U << 10), 124 BotKeyboard = (1U << 11), 125 CloudDraft = (1U << 12), 126 LocalDraftSet = (1U << 13), 127 PinnedMessages = (1U << 14), 128 129 LastUsedBit = (1U << 14), 130 }; 131 using Flags = base::flags<Flag>; is_flag_typeHistoryUpdate132 friend inline constexpr auto is_flag_type(Flag) { return true; } 133 134 not_null<History*> history; 135 Flags flags = 0; 136 137 }; 138 139 struct MessageUpdate { 140 enum class Flag : uint32 { 141 None = 0, 142 143 Edited = (1U << 0), 144 Destroyed = (1U << 1), 145 DialogRowRepaint = (1U << 2), 146 DialogRowRefresh = (1U << 3), 147 NewAdded = (1U << 4), 148 ReplyMarkup = (1U << 5), 149 BotCallbackSent = (1U << 6), 150 NewMaybeAdded = (1U << 7), 151 RepliesUnreadCount = (1U << 8), 152 153 LastUsedBit = (1U << 8), 154 }; 155 using Flags = base::flags<Flag>; is_flag_typeMessageUpdate156 friend inline constexpr auto is_flag_type(Flag) { return true; } 157 158 not_null<HistoryItem*> item; 159 Flags flags = 0; 160 161 }; 162 163 struct EntryUpdate { 164 enum class Flag : uint32 { 165 None = 0, 166 167 Repaint = (1U << 0), 168 169 LastUsedBit = (1U << 0), 170 }; 171 using Flags = base::flags<Flag>; is_flag_typeEntryUpdate172 friend inline constexpr auto is_flag_type(Flag) { return true; } 173 174 not_null<Dialogs::Entry*> entry; 175 Flags flags = 0; 176 177 }; 178 179 class Changes final { 180 public: 181 explicit Changes(not_null<Main::Session*> session); 182 183 [[nodiscard]] Main::Session &session() const; 184 185 void nameUpdated( 186 not_null<PeerData*> peer, 187 base::flat_set<QChar> oldFirstLetters); 188 [[nodiscard]] rpl::producer<NameUpdate> realtimeNameUpdates() const; 189 [[nodiscard]] rpl::producer<NameUpdate> realtimeNameUpdates( 190 not_null<PeerData*> peer) const; 191 192 void peerUpdated(not_null<PeerData*> peer, PeerUpdate::Flags flags); 193 [[nodiscard]] rpl::producer<PeerUpdate> peerUpdates( 194 PeerUpdate::Flags flags) const; 195 [[nodiscard]] rpl::producer<PeerUpdate> peerUpdates( 196 not_null<PeerData*> peer, 197 PeerUpdate::Flags flags) const; 198 [[nodiscard]] rpl::producer<PeerUpdate> peerFlagsValue( 199 not_null<PeerData*> peer, 200 PeerUpdate::Flags flags) const; 201 [[nodiscard]] rpl::producer<PeerUpdate> realtimePeerUpdates( 202 PeerUpdate::Flag flag) const; 203 204 void historyUpdated( 205 not_null<History*> history, 206 HistoryUpdate::Flags flags); 207 [[nodiscard]] rpl::producer<HistoryUpdate> historyUpdates( 208 HistoryUpdate::Flags flags) const; 209 [[nodiscard]] rpl::producer<HistoryUpdate> historyUpdates( 210 not_null<History*> history, 211 HistoryUpdate::Flags flags) const; 212 [[nodiscard]] rpl::producer<HistoryUpdate> historyFlagsValue( 213 not_null<History*> history, 214 HistoryUpdate::Flags flags) const; 215 [[nodiscard]] rpl::producer<HistoryUpdate> realtimeHistoryUpdates( 216 HistoryUpdate::Flag flag) const; 217 218 void messageUpdated( 219 not_null<HistoryItem*> item, 220 MessageUpdate::Flags flags); 221 [[nodiscard]] rpl::producer<MessageUpdate> messageUpdates( 222 MessageUpdate::Flags flags) const; 223 [[nodiscard]] rpl::producer<MessageUpdate> messageUpdates( 224 not_null<HistoryItem*> item, 225 MessageUpdate::Flags flags) const; 226 [[nodiscard]] rpl::producer<MessageUpdate> messageFlagsValue( 227 not_null<HistoryItem*> item, 228 MessageUpdate::Flags flags) const; 229 [[nodiscard]] rpl::producer<MessageUpdate> realtimeMessageUpdates( 230 MessageUpdate::Flag flag) const; 231 232 void entryUpdated( 233 not_null<Dialogs::Entry*> entry, 234 EntryUpdate::Flags flags); 235 [[nodiscard]] rpl::producer<EntryUpdate> entryUpdates( 236 EntryUpdate::Flags flags) const; 237 [[nodiscard]] rpl::producer<EntryUpdate> entryUpdates( 238 not_null<Dialogs::Entry*> entry, 239 EntryUpdate::Flags flags) const; 240 [[nodiscard]] rpl::producer<EntryUpdate> entryFlagsValue( 241 not_null<Dialogs::Entry*> entry, 242 EntryUpdate::Flags flags) const; 243 [[nodiscard]] rpl::producer<EntryUpdate> realtimeEntryUpdates( 244 EntryUpdate::Flag flag) const; 245 246 void sendNotifications(); 247 248 private: 249 template <typename DataType, typename UpdateType> 250 class Manager final { 251 public: 252 using Flag = typename UpdateType::Flag; 253 using Flags = typename UpdateType::Flags; 254 255 void updated( 256 not_null<DataType*> data, 257 Flags flags, 258 bool dropScheduled = false); 259 [[nodiscard]] rpl::producer<UpdateType> updates(Flags flags) const; 260 [[nodiscard]] rpl::producer<UpdateType> updates( 261 not_null<DataType*> data, 262 Flags flags) const; 263 [[nodiscard]] rpl::producer<UpdateType> flagsValue( 264 not_null<DataType*> data, 265 Flags flags) const; 266 [[nodiscard]] rpl::producer<UpdateType> realtimeUpdates( 267 Flag flag) const; 268 269 void sendNotifications(); 270 271 private: 272 static constexpr auto kCount = details::CountBit<Flag>(); 273 274 void sendRealtimeNotifications(not_null<DataType*> data, Flags flags); 275 276 std::array<rpl::event_stream<UpdateType>, kCount> _realtimeStreams; 277 base::flat_map<not_null<DataType*>, Flags> _updates; 278 rpl::event_stream<UpdateType> _stream; 279 280 }; 281 282 void scheduleNotifications(); 283 284 const not_null<Main::Session*> _session; 285 286 rpl::event_stream<NameUpdate> _nameStream; 287 Manager<PeerData, PeerUpdate> _peerChanges; 288 Manager<History, HistoryUpdate> _historyChanges; 289 Manager<HistoryItem, MessageUpdate> _messageChanges; 290 Manager<Dialogs::Entry, EntryUpdate> _entryChanges; 291 292 bool _notify = false; 293 294 }; 295 296 } // namespace Data 297