mirror of https://github.com/procxx/kepka.git
				
				
				
			Show cloud stickers by emoji.
This commit is contained in:
		
							parent
							
								
									c3ff5f2603
								
							
						
					
					
						commit
						f0a95032a5
					
				|  | @ -59,6 +59,7 @@ constexpr auto kFeedMessagesLimit = 50; | ||||||
| constexpr auto kReadFeaturedSetsTimeout = TimeMs(1000); | constexpr auto kReadFeaturedSetsTimeout = TimeMs(1000); | ||||||
| constexpr auto kFileLoaderQueueStopTimeout = TimeMs(5000); | constexpr auto kFileLoaderQueueStopTimeout = TimeMs(5000); | ||||||
| constexpr auto kFeedReadTimeout = TimeMs(1000); | constexpr auto kFeedReadTimeout = TimeMs(1000); | ||||||
|  | constexpr auto kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000); | ||||||
| 
 | 
 | ||||||
| bool IsSilentPost(not_null<HistoryItem*> item, bool silent) { | bool IsSilentPost(not_null<HistoryItem*> item, bool silent) { | ||||||
| 	const auto history = item->history(); | 	const auto history = item->history(); | ||||||
|  | @ -2199,11 +2200,60 @@ void ApiWrap::updateStickers() { | ||||||
| 
 | 
 | ||||||
| void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) { | void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) { | ||||||
| 	Expects(megagroup->mgInfo != nullptr); | 	Expects(megagroup->mgInfo != nullptr); | ||||||
|  | 
 | ||||||
| 	megagroup->mgInfo->stickerSet = set; | 	megagroup->mgInfo->stickerSet = set; | ||||||
| 	request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send(); | 	request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send(); | ||||||
| 	_session->data().notifyStickersUpdated(); | 	_session->data().notifyStickersUpdated(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji( | ||||||
|  | 		not_null<EmojiPtr> emoji) { | ||||||
|  | 	const auto it = _stickersByEmoji.find(emoji); | ||||||
|  | 	const auto sendRequest = [&] { | ||||||
|  | 		if (it == _stickersByEmoji.end()) { | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		const auto received = it->second.received; | ||||||
|  | 		const auto now = getms(true); | ||||||
|  | 		return (received > 0) | ||||||
|  | 			&& (received + kStickersByEmojiInvalidateTimeout) <= now; | ||||||
|  | 	}(); | ||||||
|  | 	if (sendRequest) { | ||||||
|  | 		const auto hash = (it != _stickersByEmoji.end()) | ||||||
|  | 			? it->second.hash | ||||||
|  | 			: QString(); | ||||||
|  | 		request(MTPmessages_GetStickers( | ||||||
|  | 			MTP_flags(MTPmessages_GetStickers::Flag::f_exclude_featured), | ||||||
|  | 			MTP_string(emoji->text()), | ||||||
|  | 			MTP_string(hash) | ||||||
|  | 		)).done([=](const MTPmessages_Stickers &result) { | ||||||
|  | 			if (result.type() == mtpc_messages_stickersNotModified) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			Assert(result.type() == mtpc_messages_stickers); | ||||||
|  | 			const auto &data = result.c_messages_stickers(); | ||||||
|  | 			auto &entry = _stickersByEmoji[emoji]; | ||||||
|  | 			entry.list.clear(); | ||||||
|  | 			entry.list.reserve(data.vstickers.v.size()); | ||||||
|  | 			for (const auto &sticker : data.vstickers.v) { | ||||||
|  | 				const auto document = Auth().data().document(sticker); | ||||||
|  | 				if (document->sticker()) { | ||||||
|  | 					entry.list.push_back(document); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			entry.hash = qs(data.vhash); | ||||||
|  | 			entry.received = getms(true); | ||||||
|  | 			_session->data().notifyStickersUpdated(); | ||||||
|  | 		}).send(); | ||||||
|  | 	} | ||||||
|  | 	if (it == _stickersByEmoji.end()) { | ||||||
|  | 		_stickersByEmoji.emplace(emoji, StickersByEmoji()); | ||||||
|  | 	} else if (it->second.received > 0) { | ||||||
|  | 		return &it->second.list; | ||||||
|  | 	} | ||||||
|  | 	return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ApiWrap::requestStickers(TimeId now) { | void ApiWrap::requestStickers(TimeId now) { | ||||||
| 	if (!_session->data().stickersUpdateNeeded(now) | 	if (!_session->data().stickersUpdateNeeded(now) | ||||||
| 		|| _stickersUpdateRequest) { | 		|| _stickersUpdateRequest) { | ||||||
|  |  | ||||||
|  | @ -129,6 +129,8 @@ public: | ||||||
| 	void setGroupStickerSet( | 	void setGroupStickerSet( | ||||||
| 		not_null<ChannelData*> megagroup, | 		not_null<ChannelData*> megagroup, | ||||||
| 		const MTPInputStickerSet &set); | 		const MTPInputStickerSet &set); | ||||||
|  | 	std::vector<not_null<DocumentData*>> *stickersByEmoji( | ||||||
|  | 		not_null<EmojiPtr> emoji); | ||||||
| 
 | 
 | ||||||
| 	void joinChannel(ChannelData *channel); | 	void joinChannel(ChannelData *channel); | ||||||
| 	void leaveChannel(ChannelData *channel); | 	void leaveChannel(ChannelData *channel); | ||||||
|  | @ -279,6 +281,12 @@ private: | ||||||
| 	using MessageDataRequests = QMap<MsgId, MessageDataRequest>; | 	using MessageDataRequests = QMap<MsgId, MessageDataRequest>; | ||||||
| 	using SharedMediaType = Storage::SharedMediaType; | 	using SharedMediaType = Storage::SharedMediaType; | ||||||
| 
 | 
 | ||||||
|  | 	struct StickersByEmoji { | ||||||
|  | 		std::vector<not_null<DocumentData*>> list; | ||||||
|  | 		QString hash; | ||||||
|  | 		TimeMs received = 0; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	void updatesReceived(const MTPUpdates &updates); | 	void updatesReceived(const MTPUpdates &updates); | ||||||
| 	void checkQuitPreventFinished(); | 	void checkQuitPreventFinished(); | ||||||
| 
 | 
 | ||||||
|  | @ -489,6 +497,8 @@ private: | ||||||
| 	base::Timer _featuredSetsReadTimer; | 	base::Timer _featuredSetsReadTimer; | ||||||
| 	base::flat_set<uint64> _featuredSetsRead; | 	base::flat_set<uint64> _featuredSetsRead; | ||||||
| 
 | 
 | ||||||
|  | 	base::flat_map<not_null<EmojiPtr>, StickersByEmoji> _stickersByEmoji; | ||||||
|  | 
 | ||||||
| 	base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests; | 	base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests; | ||||||
| 
 | 
 | ||||||
| 	mtpRequestId _contactsRequestId = 0; | 	mtpRequestId _contactsRequestId = 0; | ||||||
|  |  | ||||||
|  | @ -324,6 +324,7 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in | ||||||
| 		if (!isHidden()) { | 		if (!isHidden()) { | ||||||
| 			hideAnimated(); | 			hideAnimated(); | ||||||
| 		} | 		} | ||||||
|  | 		_scroll->scrollToY(0); | ||||||
| 		_mrows.clear(); | 		_mrows.clear(); | ||||||
| 		_hrows.clear(); | 		_hrows.clear(); | ||||||
| 		_brows.clear(); | 		_brows.clear(); | ||||||
|  |  | ||||||
|  | @ -670,33 +670,52 @@ Pack GetListByEmoji(not_null<EmojiPtr> emoji) { | ||||||
| 			result = faved; | 			result = faved; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	auto &order = Auth().data().stickerSetsOrder(); | 	const auto addList = [&](const Order &order, MTPDstickerSet::Flag skip) { | ||||||
| 	for (auto i = 0, l = order.size(); i != l; ++i) { | 		for (const auto setId : order) { | ||||||
| 		auto it = sets.find(order[i]); | 			auto it = sets.find(setId); | ||||||
| 		if (it != sets.cend()) { | 			if (it == sets.cend() || (it->flags & skip)) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			if (it->emoji.isEmpty()) { | 			if (it->emoji.isEmpty()) { | ||||||
| 				setsToRequest.insert(it->id, it->access); | 				setsToRequest.insert(it->id, it->access); | ||||||
| 				it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; | 				it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; | ||||||
| 			} else if (!(it->flags & MTPDstickerSet::Flag::f_archived)) { | 				continue; | ||||||
| 				auto i = it->emoji.constFind(original); | 			} | ||||||
| 				if (i != it->emoji.cend()) { | 			auto i = it->emoji.constFind(original); | ||||||
| 					result.reserve(result.size() + i->size()); | 			if (i == it->emoji.cend()) { | ||||||
| 					for_const (auto sticker, *i) { | 				continue; | ||||||
| 						if (!faved.contains(sticker)) { | 			} | ||||||
| 							result.push_back(sticker); | 			result.reserve(result.size() + i->size()); | ||||||
| 						} | 			for_const (const auto document, *i) { | ||||||
| 					} | 				if (!faved.contains(document)) { | ||||||
|  | 					result.push_back(document); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	}; | ||||||
|  | 
 | ||||||
|  | 	addList( | ||||||
|  | 		Auth().data().stickerSetsOrder(), | ||||||
|  | 		MTPDstickerSet::Flag::f_archived); | ||||||
|  | 	addList( | ||||||
|  | 		Auth().data().featuredStickerSetsOrder(), | ||||||
|  | 		MTPDstickerSet::Flag::f_installed_date); | ||||||
|  | 
 | ||||||
| 	if (!setsToRequest.isEmpty()) { | 	if (!setsToRequest.isEmpty()) { | ||||||
| 		for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { | 		for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { | ||||||
| 			Auth().api().scheduleStickerSetRequest(i.key(), i.value()); | 			Auth().api().scheduleStickerSetRequest(i.key(), i.value()); | ||||||
| 		} | 		} | ||||||
| 		Auth().api().requestStickerSets(); | 		Auth().api().requestStickerSets(); | ||||||
| 	} | 	} | ||||||
| 	return result; | 	if (const auto pack = Auth().api().stickersByEmoji(original)) { | ||||||
|  | 		for (const auto document : *pack) { | ||||||
|  | 			if (!base::contains(result, document)) { | ||||||
|  | 				result.push_back(document); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return result; | ||||||
|  | 	} | ||||||
|  | 	return Pack(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet( | base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet( | ||||||
|  |  | ||||||
|  | @ -43,13 +43,13 @@ public: | ||||||
| 		return *_session; | 		return *_session; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	base::Variable<bool> &contactsLoaded() { | 	[[nodiscard]] base::Variable<bool> &contactsLoaded() { | ||||||
| 		return _contactsLoaded; | 		return _contactsLoaded; | ||||||
| 	} | 	} | ||||||
| 	base::Variable<bool> &allChatsLoaded() { | 	[[nodiscard]] base::Variable<bool> &allChatsLoaded() { | ||||||
| 		return _allChatsLoaded; | 		return _allChatsLoaded; | ||||||
| 	} | 	} | ||||||
| 	base::Observable<void> &moreChatsLoaded() { | 	[[nodiscard]] base::Observable<void> &moreChatsLoaded() { | ||||||
| 		return _moreChatsLoaded; | 		return _moreChatsLoaded; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -57,7 +57,7 @@ public: | ||||||
| 		not_null<HistoryItem*> item; | 		not_null<HistoryItem*> item; | ||||||
| 		not_null<bool*> isVisible; | 		not_null<bool*> isVisible; | ||||||
| 	}; | 	}; | ||||||
| 	base::Observable<ItemVisibilityQuery> &queryItemVisibility() { | 	[[nodiscard]] base::Observable<ItemVisibilityQuery> &queryItemVisibility() { | ||||||
| 		return _queryItemVisibility; | 		return _queryItemVisibility; | ||||||
| 	} | 	} | ||||||
| 	struct IdChange { | 	struct IdChange { | ||||||
|  | @ -65,32 +65,32 @@ public: | ||||||
| 		MsgId oldId = 0; | 		MsgId oldId = 0; | ||||||
| 	}; | 	}; | ||||||
| 	void notifyItemIdChange(IdChange event); | 	void notifyItemIdChange(IdChange event); | ||||||
| 	rpl::producer<IdChange> itemIdChanged() const; | 	[[nodiscard]] rpl::producer<IdChange> itemIdChanged() const; | ||||||
| 	void notifyItemLayoutChange(not_null<const HistoryItem*> item); | 	void notifyItemLayoutChange(not_null<const HistoryItem*> item); | ||||||
| 	rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const; | 	[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const; | ||||||
| 	void notifyViewLayoutChange(not_null<const ViewElement*> view); | 	void notifyViewLayoutChange(not_null<const ViewElement*> view); | ||||||
| 	rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const; | 	[[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const; | ||||||
| 	void requestItemRepaint(not_null<const HistoryItem*> item); | 	void requestItemRepaint(not_null<const HistoryItem*> item); | ||||||
| 	rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const; | 	[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const; | ||||||
| 	void requestViewRepaint(not_null<const ViewElement*> view); | 	void requestViewRepaint(not_null<const ViewElement*> view); | ||||||
| 	rpl::producer<not_null<const ViewElement*>> viewRepaintRequest() const; | 	[[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewRepaintRequest() const; | ||||||
| 	void requestItemResize(not_null<const HistoryItem*> item); | 	void requestItemResize(not_null<const HistoryItem*> item); | ||||||
| 	rpl::producer<not_null<const HistoryItem*>> itemResizeRequest() const; | 	[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemResizeRequest() const; | ||||||
| 	void requestViewResize(not_null<ViewElement*> view); | 	void requestViewResize(not_null<ViewElement*> view); | ||||||
| 	rpl::producer<not_null<ViewElement*>> viewResizeRequest() const; | 	[[nodiscard]] rpl::producer<not_null<ViewElement*>> viewResizeRequest() const; | ||||||
| 	void requestItemViewRefresh(not_null<HistoryItem*> item); | 	void requestItemViewRefresh(not_null<HistoryItem*> item); | ||||||
| 	rpl::producer<not_null<HistoryItem*>> itemViewRefreshRequest() const; | 	[[nodiscard]] rpl::producer<not_null<HistoryItem*>> itemViewRefreshRequest() const; | ||||||
| 	void requestAnimationPlayInline(not_null<HistoryItem*> item); | 	void requestAnimationPlayInline(not_null<HistoryItem*> item); | ||||||
| 	rpl::producer<not_null<HistoryItem*>> animationPlayInlineRequest() const; | 	[[nodiscard]] rpl::producer<not_null<HistoryItem*>> animationPlayInlineRequest() const; | ||||||
| 	void notifyHistoryUnloaded(not_null<const History*> history); | 	void notifyHistoryUnloaded(not_null<const History*> history); | ||||||
| 	rpl::producer<not_null<const History*>> historyUnloaded() const; | 	[[nodiscard]] rpl::producer<not_null<const History*>> historyUnloaded() const; | ||||||
| 
 | 
 | ||||||
| 	void notifyItemRemoved(not_null<const HistoryItem*> item); | 	void notifyItemRemoved(not_null<const HistoryItem*> item); | ||||||
| 	rpl::producer<not_null<const HistoryItem*>> itemRemoved() const; | 	[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRemoved() const; | ||||||
| 	void notifyHistoryCleared(not_null<const History*> history); | 	void notifyHistoryCleared(not_null<const History*> history); | ||||||
| 	rpl::producer<not_null<const History*>> historyCleared() const; | 	[[nodiscard]] rpl::producer<not_null<const History*>> historyCleared() const; | ||||||
| 	void notifyHistoryChangeDelayed(not_null<History*> history); | 	void notifyHistoryChangeDelayed(not_null<History*> history); | ||||||
| 	rpl::producer<not_null<History*>> historyChanged() const; | 	[[nodiscard]] rpl::producer<not_null<History*>> historyChanged() const; | ||||||
| 	void sendHistoryChangeNotifications(); | 	void sendHistoryChangeNotifications(); | ||||||
| 
 | 
 | ||||||
| 	using MegagroupParticipant = std::tuple< | 	using MegagroupParticipant = std::tuple< | ||||||
|  | @ -99,23 +99,23 @@ public: | ||||||
| 	void removeMegagroupParticipant( | 	void removeMegagroupParticipant( | ||||||
| 		not_null<ChannelData*> channel, | 		not_null<ChannelData*> channel, | ||||||
| 		not_null<UserData*> user); | 		not_null<UserData*> user); | ||||||
| 	rpl::producer<MegagroupParticipant> megagroupParticipantRemoved() const; | 	[[nodiscard]] rpl::producer<MegagroupParticipant> megagroupParticipantRemoved() const; | ||||||
| 	rpl::producer<not_null<UserData*>> megagroupParticipantRemoved( | 	[[nodiscard]] rpl::producer<not_null<UserData*>> megagroupParticipantRemoved( | ||||||
| 		not_null<ChannelData*> channel) const; | 		not_null<ChannelData*> channel) const; | ||||||
| 	void addNewMegagroupParticipant( | 	void addNewMegagroupParticipant( | ||||||
| 		not_null<ChannelData*> channel, | 		not_null<ChannelData*> channel, | ||||||
| 		not_null<UserData*> user); | 		not_null<UserData*> user); | ||||||
| 	rpl::producer<MegagroupParticipant> megagroupParticipantAdded() const; | 	[[nodiscard]] rpl::producer<MegagroupParticipant> megagroupParticipantAdded() const; | ||||||
| 	rpl::producer<not_null<UserData*>> megagroupParticipantAdded( | 	[[nodiscard]] rpl::producer<not_null<UserData*>> megagroupParticipantAdded( | ||||||
| 		not_null<ChannelData*> channel) const; | 		not_null<ChannelData*> channel) const; | ||||||
| 
 | 
 | ||||||
| 	void notifyFeedUpdated(not_null<Feed*> feed, FeedUpdateFlag update); | 	void notifyFeedUpdated(not_null<Feed*> feed, FeedUpdateFlag update); | ||||||
| 	rpl::producer<FeedUpdate> feedUpdated() const; | 	[[nodiscard]] rpl::producer<FeedUpdate> feedUpdated() const; | ||||||
| 
 | 
 | ||||||
| 	void notifyStickersUpdated(); | 	void notifyStickersUpdated(); | ||||||
| 	rpl::producer<> stickersUpdated() const; | 	[[nodiscard]] rpl::producer<> stickersUpdated() const; | ||||||
| 	void notifySavedGifsUpdated(); | 	void notifySavedGifsUpdated(); | ||||||
| 	rpl::producer<> savedGifsUpdated() const; | 	[[nodiscard]] rpl::producer<> savedGifsUpdated() const; | ||||||
| 
 | 
 | ||||||
| 	bool stickersUpdateNeeded(TimeMs now) const { | 	bool stickersUpdateNeeded(TimeMs now) const { | ||||||
| 		return stickersUpdateNeeded(_lastStickersUpdate, now); | 		return stickersUpdateNeeded(_lastStickersUpdate, now); | ||||||
|  | @ -153,7 +153,7 @@ public: | ||||||
| 	void setFeaturedStickerSetsUnreadCount(int count) { | 	void setFeaturedStickerSetsUnreadCount(int count) { | ||||||
| 		_featuredStickerSetsUnreadCount = count; | 		_featuredStickerSetsUnreadCount = count; | ||||||
| 	} | 	} | ||||||
| 	rpl::producer<int> featuredStickerSetsUnreadCountValue() const { | 	[[nodiscard]] rpl::producer<int> featuredStickerSetsUnreadCountValue() const { | ||||||
| 		return _featuredStickerSetsUnreadCount.value(); | 		return _featuredStickerSetsUnreadCount.value(); | ||||||
| 	} | 	} | ||||||
| 	const Stickers::Sets &stickerSets() const { | 	const Stickers::Sets &stickerSets() const { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue