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/flat_map.h"
11 
12 #include "dialogs/dialogs_key.h"
13 
14 namespace Main {
15 class Session;
16 } // namespace Main
17 
18 namespace Data {
19 class Session;
20 class Folder;
21 class CloudImageView;
22 } // namespace Data
23 
24 namespace Dialogs {
25 
26 class Row;
27 class IndexedList;
28 class MainList;
29 
30 struct RowsByLetter {
31 	not_null<Row*> main;
32 	base::flat_map<QChar, not_null<Row*>> letters;
33 };
34 
35 enum class SortMode {
36 	Date    = 0x00,
37 	Name    = 0x01,
38 	Add     = 0x02,
39 };
40 
41 struct PositionChange {
42 	int from = -1;
43 	int to = -1;
44 };
45 
46 struct UnreadState {
47 	int messages = 0;
48 	int messagesMuted = 0;
49 	int chats = 0;
50 	int chatsMuted = 0;
51 	int marks = 0;
52 	int marksMuted = 0;
53 	bool known = false;
54 
55 	UnreadState &operator+=(const UnreadState &other) {
56 		messages += other.messages;
57 		messagesMuted += other.messagesMuted;
58 		chats += other.chats;
59 		chatsMuted += other.chatsMuted;
60 		marks += other.marks;
61 		marksMuted += other.marksMuted;
62 		return *this;
63 	}
64 	UnreadState &operator-=(const UnreadState &other) {
65 		messages -= other.messages;
66 		messagesMuted -= other.messagesMuted;
67 		chats -= other.chats;
68 		chatsMuted -= other.chatsMuted;
69 		marks -= other.marks;
70 		marksMuted -= other.marksMuted;
71 		return *this;
72 	}
73 
emptyUnreadState74 	bool empty() const {
75 		return !messages && !chats && !marks;
76 	}
77 };
78 
79 inline UnreadState operator+(const UnreadState &a, const UnreadState &b) {
80 	auto result = a;
81 	result += b;
82 	return result;
83 }
84 
85 inline UnreadState operator-(const UnreadState &a, const UnreadState &b) {
86 	auto result = a;
87 	result -= b;
88 	return result;
89 }
90 
91 class Entry {
92 public:
93 	enum class Type {
94 		History,
95 		Folder,
96 	};
97 	Entry(not_null<Data::Session*> owner, Type type);
98 	Entry(const Entry &other) = delete;
99 	Entry &operator=(const Entry &other) = delete;
100 	virtual ~Entry() = default;
101 
102 	[[nodiscard]] Data::Session &owner() const;
103 	[[nodiscard]] Main::Session &session() const;
104 
105 	History *asHistory();
106 	Data::Folder *asFolder();
107 
108 	PositionChange adjustByPosInChatList(
109 		FilterId filterId,
110 		not_null<MainList*> list);
111 	[[nodiscard]] bool inChatList(FilterId filterId = 0) const {
112 		return _chatListLinks.contains(filterId);
113 	}
114 	RowsByLetter *chatListLinks(FilterId filterId);
115 	const RowsByLetter *chatListLinks(FilterId filterId) const;
116 	[[nodiscard]] int posInChatList(FilterId filterId) const;
117 	not_null<Row*> addToChatList(
118 		FilterId filterId,
119 		not_null<MainList*> list);
120 	void removeFromChatList(
121 		FilterId filterId,
122 		not_null<MainList*> list);
123 	void removeChatListEntryByLetter(FilterId filterId, QChar letter);
124 	void addChatListEntryByLetter(
125 		FilterId filterId,
126 		QChar letter,
127 		not_null<Row*> row);
128 	void updateChatListEntry();
isPinnedDialog(FilterId filterId)129 	[[nodiscard]] bool isPinnedDialog(FilterId filterId) const {
130 		return lookupPinnedIndex(filterId) != 0;
131 	}
132 	void cachePinnedIndex(FilterId filterId, int index);
133 	[[nodiscard]] bool isTopPromoted() const;
sortKeyInChatList(FilterId filterId)134 	[[nodiscard]] uint64 sortKeyInChatList(FilterId filterId) const {
135 		return filterId
136 			? computeSortPosition(filterId)
137 			: _sortKeyInChatList;
138 	}
139 	void updateChatListSortPosition();
140 	void setChatListTimeId(TimeId date);
141 	virtual void updateChatListExistence();
142 	bool needUpdateInChatList() const;
143 	virtual TimeId adjustedChatListTimeId() const;
144 
145 	virtual int fixedOnTopIndex() const = 0;
146 	static constexpr auto kArchiveFixOnTopIndex = 1;
147 	static constexpr auto kTopPromotionFixOnTopIndex = 2;
148 
149 	virtual bool shouldBeInChatList() const = 0;
150 	virtual int chatListUnreadCount() const = 0;
151 	virtual bool chatListUnreadMark() const = 0;
152 	virtual bool chatListMutedBadge() const = 0;
153 	virtual UnreadState chatListUnreadState() const = 0;
154 	virtual HistoryItem *chatListMessage() const = 0;
155 	virtual bool chatListMessageKnown() const = 0;
156 	virtual void requestChatListMessage() = 0;
157 	virtual const QString &chatListName() const = 0;
158 	virtual const QString &chatListNameSortKey() const = 0;
159 	virtual const base::flat_set<QString> &chatListNameWords() const = 0;
160 	virtual const base::flat_set<QChar> &chatListFirstLetters() const = 0;
161 
folderKnown()162 	virtual bool folderKnown() const {
163 		return true;
164 	}
folder()165 	virtual Data::Folder *folder() const {
166 		return nullptr;
167 	}
168 
169 	virtual void loadUserpic() = 0;
170 	virtual void paintUserpic(
171 		Painter &p,
172 		std::shared_ptr<Data::CloudImageView> &view,
173 		int x,
174 		int y,
175 		int size) const = 0;
paintUserpicLeft(Painter & p,std::shared_ptr<Data::CloudImageView> & view,int x,int y,int w,int size)176 	void paintUserpicLeft(
177 			Painter &p,
178 			std::shared_ptr<Data::CloudImageView> &view,
179 			int x,
180 			int y,
181 			int w,
182 			int size) const {
183 		paintUserpic(p, view, rtl() ? (w - x - size) : x, y, size);
184 	}
185 
chatListTimeId()186 	[[nodiscard]] TimeId chatListTimeId() const {
187 		return _timeId;
188 	}
189 
190 protected:
191 	void notifyUnreadStateChange(const UnreadState &wasState);
unreadStateChangeNotifier(bool required)192 	auto unreadStateChangeNotifier(bool required) {
193 		const auto notify = required && inChatList();
194 		const auto wasState = notify ? chatListUnreadState() : UnreadState();
195 		return gsl::finally([=] {
196 			if (notify) {
197 				notifyUnreadStateChange(wasState);
198 			}
199 		});
200 	}
201 
202 	[[nodiscard]] int lookupPinnedIndex(FilterId filterId) const;
203 
204 	void cacheTopPromoted(bool promoted);
205 
206 private:
207 	virtual void changedChatListPinHook();
208 	void pinnedIndexChanged(int was, int now);
209 	[[nodiscard]] uint64 computeSortPosition(FilterId filterId) const;
210 
211 	void setChatListExistence(bool exists);
212 	not_null<Row*> mainChatListLink(FilterId filterId) const;
213 	Row *maybeMainChatListLink(FilterId filterId) const;
214 
215 	const not_null<Data::Session*> _owner;
216 	base::flat_map<FilterId, RowsByLetter> _chatListLinks;
217 	uint64 _sortKeyInChatList = 0;
218 	uint64 _sortKeyByDate = 0;
219 	base::flat_map<FilterId, int> _pinnedIndex;
220 	TimeId _timeId = 0;
221 	bool _isTopPromoted = false;
222 	const bool _isFolder = false;
223 
224 };
225 
226 } // namespace Dialogs
227