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