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