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 "storage/storage_shared_media.h"
11 #include "base/weak_ptr.h"
12 #include "data/data_sparse_ids.h"
13 
14 class History;
15 
16 namespace Main {
17 class Session;
18 } // namespace Main
19 
20 std::optional<Storage::SharedMediaType> SharedMediaOverviewType(
21 	Storage::SharedMediaType type);
22 void SharedMediaShowOverview(
23 	Storage::SharedMediaType type,
24 	not_null<History*> history);
25 bool SharedMediaAllowSearch(Storage::SharedMediaType type);
26 
27 rpl::producer<SparseIdsSlice> SharedMediaViewer(
28 	not_null<Main::Session*> session,
29 	Storage::SharedMediaKey key,
30 	int limitBefore,
31 	int limitAfter);
32 
33 struct SharedMediaMergedKey {
34 	using Type = Storage::SharedMediaType;
35 
SharedMediaMergedKeySharedMediaMergedKey36 	SharedMediaMergedKey(
37 		SparseIdsMergedSlice::Key mergedKey,
38 		Type type)
39 	: mergedKey(mergedKey)
40 	, type(type) {
41 	}
42 
43 	bool operator==(const SharedMediaMergedKey &other) const {
44 		return (mergedKey == other.mergedKey)
45 			&& (type == other.type);
46 	}
47 
48 	SparseIdsMergedSlice::Key mergedKey;
49 	Type type = Type::kCount;
50 
51 };
52 
53 rpl::producer<SparseIdsMergedSlice> SharedScheduledMediaViewer(
54 	not_null<Main::Session*> session,
55 	SharedMediaMergedKey key,
56 	int limitBefore,
57 	int limitAfter);
58 
59 rpl::producer<SparseIdsMergedSlice> SharedMediaMergedViewer(
60 	not_null<Main::Session*> session,
61 	SharedMediaMergedKey key,
62 	int limitBefore,
63 	int limitAfter);
64 
65 class SharedMediaWithLastSlice {
66 public:
67 	using Type = Storage::SharedMediaType;
68 
69 	using Value = std::variant<FullMsgId, not_null<PhotoData*>>;
70 	using MessageId = SparseIdsMergedSlice::UniversalMsgId;
71 	using UniversalMsgId = std::variant<
72 		MessageId,
73 		not_null<PhotoData*>>;
74 
75 	struct Key {
76 		Key(
77 			PeerId peerId,
78 			PeerId migratedPeerId,
79 			Type type,
80 			UniversalMsgId universalId,
81 			bool scheduled = false)
peerIdKey82 		: peerId(peerId)
83 		, migratedPeerId(migratedPeerId)
84 		, type(type)
85 		, universalId(universalId)
86 		, scheduled(scheduled) {
87 			Expects(v::is<MessageId>(universalId) || type == Type::ChatPhoto);
88 		}
89 
90 		bool operator==(const Key &other) const {
91 			return (peerId == other.peerId)
92 				&& (migratedPeerId == other.migratedPeerId)
93 				&& (type == other.type)
94 				&& (universalId == other.universalId);
95 		}
96 		bool operator!=(const Key &other) const {
97 			return !(*this == other);
98 		}
99 
100 		PeerId peerId = 0;
101 		PeerId migratedPeerId = 0;
102 		Type type = Type::kCount;
103 		UniversalMsgId universalId;
104 		bool scheduled = false;
105 
106 	};
107 
108 	SharedMediaWithLastSlice(
109 		not_null<Main::Session*> session,
110 		Key key);
111 	SharedMediaWithLastSlice(
112 		not_null<Main::Session*> session,
113 		Key key,
114 		SparseIdsMergedSlice slice,
115 		std::optional<SparseIdsMergedSlice> ending);
116 
117 	std::optional<int> fullCount() const;
118 	std::optional<int> skippedBefore() const;
119 	std::optional<int> skippedAfter() const;
120 	std::optional<int> indexOf(Value fullId) const;
121 	int size() const;
122 	Value operator[](int index) const;
123 	std::optional<int> distance(const Key &a, const Key &b) const;
124 
125 	void reverse();
126 
ViewerKey(const Key & key)127 	static SparseIdsMergedSlice::Key ViewerKey(const Key &key) {
128 		return {
129 			key.peerId,
130 			key.migratedPeerId,
131 			v::is<MessageId>(key.universalId)
132 				? v::get<MessageId>(key.universalId)
133 				: ServerMaxMsgId - 1
134 		};
135 	}
EndingKey(const Key & key)136 	static SparseIdsMergedSlice::Key EndingKey(const Key &key) {
137 		return {
138 			key.peerId,
139 			key.migratedPeerId,
140 			ServerMaxMsgId - 1
141 		};
142 	}
143 
144 private:
EndingSlice(const Key & key)145 	static std::optional<SparseIdsMergedSlice> EndingSlice(const Key &key) {
146 		return v::is<MessageId>(key.universalId)
147 			? base::make_optional(SparseIdsMergedSlice(EndingKey(key)))
148 			: std::nullopt;
149 	}
150 
151 	static std::optional<PhotoId> LastPeerPhotoId(
152 		not_null<Main::Session*> session,
153 		PeerId peerId);
154 	static std::optional<bool> IsLastIsolated(
155 		not_null<Main::Session*> session,
156 		const SparseIdsMergedSlice &slice,
157 		const std::optional<SparseIdsMergedSlice> &ending,
158 		std::optional<PhotoId> lastPeerPhotoId);
159 	static std::optional<FullMsgId> LastFullMsgId(
160 		const SparseIdsMergedSlice &slice);
Add(const std::optional<int> & a,const std::optional<int> & b)161 	static std::optional<int> Add(
162 			const std::optional<int> &a,
163 			const std::optional<int> &b) {
164 		return (a && b) ? base::make_optional(*a + *b) : std::nullopt;
165 	}
ComputeId(PeerId peerId,MsgId msgId)166 	static Value ComputeId(PeerId peerId, MsgId msgId) {
167 		return FullMsgId(peerToChannel(peerId), msgId);
168 	}
ComputeId(const Key & key)169 	static Value ComputeId(const Key &key) {
170 		if (const auto messageId = std::get_if<MessageId>(&key.universalId)) {
171 			return (*messageId >= 0)
172 				? ComputeId(key.peerId, *messageId)
173 				: ComputeId(key.migratedPeerId, ServerMaxMsgId + *messageId);
174 		}
175 		return v::get<not_null<PhotoData*>>(key.universalId);
176 	}
177 
isolatedInSlice()178 	bool isolatedInSlice() const {
179 		return (_slice.skippedAfter() != 0);
180 	}
lastPhotoSkip()181 	std::optional<int> lastPhotoSkip() const {
182 		return _isolatedLastPhoto
183 			| [](bool isolated) { return isolated ? 1 : 0; };
184 	}
185 
186 	std::optional<int> skippedBeforeImpl() const;
187 	std::optional<int> skippedAfterImpl() const;
188 	std::optional<int> indexOfImpl(Value fullId) const;
189 
190 	not_null<Main::Session*> _session;
191 	Key _key;
192 	SparseIdsMergedSlice _slice;
193 	std::optional<SparseIdsMergedSlice> _ending;
194 	std::optional<PhotoId> _lastPhotoId;
195 	std::optional<bool> _isolatedLastPhoto;
196 	bool _reversed = false;
197 
198 };
199 
200 rpl::producer<SharedMediaWithLastSlice> SharedMediaWithLastViewer(
201 	not_null<Main::Session*> session,
202 	SharedMediaWithLastSlice::Key key,
203 	int limitBefore,
204 	int limitAfter);
205 
206 rpl::producer<SharedMediaWithLastSlice> SharedMediaWithLastReversedViewer(
207 	not_null<Main::Session*> session,
208 	SharedMediaWithLastSlice::Key key,
209 	int limitBefore,
210 	int limitAfter);
211