Moved sticker randomization to class in menu item of userpic builder.
This commit is contained in:
		
							parent
							
								
									08644a9c31
								
							
						
					
					
						commit
						e6b24a49f6
					
				
					 2 changed files with 143 additions and 59 deletions
				
			
		|  | @ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "base/random.h" | #include "base/random.h" | ||||||
| #include "base/timer.h" | #include "base/timer.h" | ||||||
| #include "data/data_document.h" | #include "data/data_document.h" | ||||||
|  | #include "data/data_document_media.h" | ||||||
| #include "data/data_session.h" | #include "data/data_session.h" | ||||||
| #include "data/stickers/data_custom_emoji.h" | #include "data/stickers/data_custom_emoji.h" | ||||||
| #include "info/userpic/info_userpic_emoji_builder.h" | #include "info/userpic/info_userpic_emoji_builder.h" | ||||||
|  | @ -27,6 +28,128 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include <random> | #include <random> | ||||||
| 
 | 
 | ||||||
| namespace UserpicBuilder { | namespace UserpicBuilder { | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | constexpr auto kTimeout = crl::time(1500); | ||||||
|  | 
 | ||||||
|  | class StickerProvider final { | ||||||
|  | public: | ||||||
|  | 	StickerProvider(not_null<Data::Session*> owner); | ||||||
|  | 
 | ||||||
|  | 	void setDocuments(std::vector<DocumentId> documents); | ||||||
|  | 	[[nodiscard]] DocumentId documentId() const; | ||||||
|  | 	[[nodiscard]] auto documentChanged() const | ||||||
|  | 	-> rpl::producer<not_null<DocumentData*>>; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	void processDocumentIndex(int documentIndex); | ||||||
|  | 	[[nodiscard]] DocumentData *lookupAndRememberSticker(int documentIndex); | ||||||
|  | 	[[nodiscard]] std::pair<DocumentData*, int> lookupSticker( | ||||||
|  | 		int documentIndex) const; | ||||||
|  | 
 | ||||||
|  | 	const not_null<Data::Session*> _owner; | ||||||
|  | 
 | ||||||
|  | 	int _documentIndex = 0; | ||||||
|  | 	std::vector<DocumentId> _shuffledDocuments; | ||||||
|  | 
 | ||||||
|  | 	base::Timer _timer; | ||||||
|  | 
 | ||||||
|  | 	rpl::event_stream<not_null<DocumentData*>> _documentChanged; | ||||||
|  | 	rpl::lifetime _resolvingLifetime; | ||||||
|  | 	rpl::lifetime _downloadFinishedLifetime; | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | StickerProvider::StickerProvider(not_null<Data::Session*> owner) | ||||||
|  | : _owner(owner) { | ||||||
|  | 	_timer.setCallback([=] { | ||||||
|  | 		_documentIndex++; | ||||||
|  | 		if (_documentIndex >= _shuffledDocuments.size()) { | ||||||
|  | 			_documentIndex = 0; | ||||||
|  | 		} | ||||||
|  | 		processDocumentIndex(_documentIndex); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DocumentId StickerProvider::documentId() const { | ||||||
|  | 	const auto &[document, index] = lookupSticker(_documentIndex); | ||||||
|  | 	return document ? document->id : DocumentId(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void StickerProvider::setDocuments(std::vector<DocumentId> documents) { | ||||||
|  | 	if (documents.empty()) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	auto rd = std::random_device(); | ||||||
|  | 	ranges::shuffle(documents, std::mt19937(rd())); | ||||||
|  | 	_shuffledDocuments = std::move(documents); | ||||||
|  | 	_documentIndex = 0; | ||||||
|  | 	processDocumentIndex(_documentIndex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | auto StickerProvider::documentChanged() const | ||||||
|  | -> rpl::producer<not_null<DocumentData*>> { | ||||||
|  | 	return _documentChanged.events(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void StickerProvider::processDocumentIndex(int documentIndex) { | ||||||
|  | 	if (const auto document = lookupAndRememberSticker(documentIndex)) { | ||||||
|  | 		_resolvingLifetime.destroy(); | ||||||
|  | 		_owner->customEmojiManager().resolve( | ||||||
|  | 			document->id | ||||||
|  | 		) | rpl::start_with_next([=](not_null<DocumentData*> d) { | ||||||
|  | 			_resolvingLifetime.destroy(); | ||||||
|  | 			_downloadFinishedLifetime.destroy(); | ||||||
|  | 
 | ||||||
|  | 			const auto mediaView = d->createMediaView(); | ||||||
|  | 			_downloadFinishedLifetime.add([=] { | ||||||
|  | 				[[maybe_unused]] const auto copy = mediaView; | ||||||
|  | 			}); | ||||||
|  | 			mediaView->checkStickerLarge(); | ||||||
|  | 			mediaView->goodThumbnailWanted(); | ||||||
|  | 			rpl::single( | ||||||
|  | 				rpl::empty_value() | ||||||
|  | 			) | rpl::then( | ||||||
|  | 				_owner->session().downloaderTaskFinished() | ||||||
|  | 			) | rpl::start_with_next([=] { | ||||||
|  | 				if (mediaView->loaded()) { | ||||||
|  | 					_timer.callOnce(kTimeout); | ||||||
|  | 					_documentChanged.fire_copy(mediaView->owner()); | ||||||
|  | 					_downloadFinishedLifetime.destroy(); | ||||||
|  | 				} | ||||||
|  | 			}, _downloadFinishedLifetime); | ||||||
|  | 		}, _resolvingLifetime); | ||||||
|  | 	} else if (!_resolvingLifetime) { | ||||||
|  | 		_timer.callOnce(kTimeout); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DocumentData *StickerProvider::lookupAndRememberSticker(int documentIndex) { | ||||||
|  | 	const auto &[document, index] = lookupSticker(documentIndex); | ||||||
|  | 	if (document) { | ||||||
|  | 		_documentIndex = index; | ||||||
|  | 	} | ||||||
|  | 	return document; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::pair<DocumentData*, int> StickerProvider::lookupSticker( | ||||||
|  | 		int documentIndex) const { | ||||||
|  | 	const auto size = _shuffledDocuments.size(); | ||||||
|  | 	for (auto i = 0; i < size; i++) { | ||||||
|  | 		const auto unrestrictedIndex = documentIndex + i; | ||||||
|  | 		const auto index = (unrestrictedIndex >= size) | ||||||
|  | 			? (unrestrictedIndex - size) | ||||||
|  | 			: unrestrictedIndex; | ||||||
|  | 		const auto id = _shuffledDocuments[index]; | ||||||
|  | 		const auto document = _owner->document(id); | ||||||
|  | 		if (document->sticker()) { | ||||||
|  | 			return { document, index }; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return { nullptr, 0 }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
| 
 | 
 | ||||||
| void AddEmojiBuilderAction( | void AddEmojiBuilderAction( | ||||||
| 		not_null<Window::SessionController*> controller, | 		not_null<Window::SessionController*> controller, | ||||||
|  | @ -34,35 +157,23 @@ void AddEmojiBuilderAction( | ||||||
| 		rpl::producer<std::vector<DocumentId>> documents, | 		rpl::producer<std::vector<DocumentId>> documents, | ||||||
| 		Fn<void(UserpicBuilder::Result)> &&done, | 		Fn<void(UserpicBuilder::Result)> &&done, | ||||||
| 		bool isForum) { | 		bool isForum) { | ||||||
| 	constexpr auto kTimeout = crl::time(1500); |  | ||||||
| 	struct State final { |  | ||||||
| 		State() { |  | ||||||
| 			colorIndex = base::RandomIndex(std::numeric_limits<int>::max()); |  | ||||||
| 		} |  | ||||||
| 		void next() { |  | ||||||
| 			auto nextIndex = documentIndex.current() + 1; |  | ||||||
| 			if (nextIndex >= shuffledDocuments.size()) { |  | ||||||
| 				nextIndex = 0; |  | ||||||
| 			} |  | ||||||
| 			documentIndex = nextIndex; |  | ||||||
| 		} |  | ||||||
| 		void documentShown() { |  | ||||||
| 			if (!firstDocumentShown) { |  | ||||||
| 				firstDocumentShown = true; |  | ||||||
| 			} else { |  | ||||||
| 				colorIndex = base::RandomIndex( |  | ||||||
| 					std::numeric_limits<int>::max()); |  | ||||||
| 			} |  | ||||||
| 			timer.callOnce(kTimeout); |  | ||||||
| 		} |  | ||||||
| 		rpl::variable<int> documentIndex; |  | ||||||
| 		rpl::variable<int> colorIndex; |  | ||||||
| 		std::vector<DocumentId> shuffledDocuments; |  | ||||||
| 		bool firstDocumentShown = false; |  | ||||||
| 
 | 
 | ||||||
| 		base::Timer timer; | 	struct State final { | ||||||
|  | 		State(not_null<Window::SessionController*> controller) | ||||||
|  | 		: manager(&controller->session().data()) | ||||||
|  | 		, colorIndex(rpl::single( | ||||||
|  | 			rpl::empty_value() | ||||||
|  | 		) | rpl::then( | ||||||
|  | 			manager.documentChanged() | rpl::skip(1) | rpl::to_empty | ||||||
|  | 		) | rpl::map([] { | ||||||
|  | 			return base::RandomIndex(std::numeric_limits<int>::max()); | ||||||
|  | 		})) { | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		StickerProvider manager; | ||||||
|  | 		rpl::variable<int> colorIndex; | ||||||
| 	}; | 	}; | ||||||
| 	const auto state = menu->lifetime().make_state<State>(); | 	const auto state = menu->lifetime().make_state<State>(controller); | ||||||
| 	auto item = base::make_unique_q<Ui::Menu::Action>( | 	auto item = base::make_unique_q<Ui::Menu::Action>( | ||||||
| 		menu.get(), | 		menu.get(), | ||||||
| 		menu->st().menu, | 		menu->st().menu, | ||||||
|  | @ -70,10 +181,7 @@ void AddEmojiBuilderAction( | ||||||
| 			menu.get(), | 			menu.get(), | ||||||
| 			tr::lng_attach_profile_emoji(tr::now), | 			tr::lng_attach_profile_emoji(tr::now), | ||||||
| 			[=, done = std::move(done), docs = rpl::duplicate(documents)] { | 			[=, done = std::move(done), docs = rpl::duplicate(documents)] { | ||||||
| 				const auto index = state->documentIndex.current(); | 				const auto id = state->manager.documentId(); | ||||||
| 				const auto id = index < state->shuffledDocuments.size() |  | ||||||
| 					? state->shuffledDocuments[index] |  | ||||||
| 					: 0; |  | ||||||
| 				UserpicBuilder::ShowLayer( | 				UserpicBuilder::ShowLayer( | ||||||
| 					controller, | 					controller, | ||||||
| 					{ id, state->colorIndex.current(), docs, {}, isForum }, | 					{ id, state->colorIndex.current(), docs, {}, isForum }, | ||||||
|  | @ -81,29 +189,10 @@ void AddEmojiBuilderAction( | ||||||
| 			}), | 			}), | ||||||
| 		nullptr, | 		nullptr, | ||||||
| 		nullptr); | 		nullptr); | ||||||
| 	state->timer.setCallback([=] { state->next(); }); |  | ||||||
| 	const auto icon = UserpicBuilder::CreateEmojiUserpic( | 	const auto icon = UserpicBuilder::CreateEmojiUserpic( | ||||||
| 		item.get(), | 		item.get(), | ||||||
| 		st::restoreUserpicIcon.size, | 		st::restoreUserpicIcon.size, | ||||||
| 		state->documentIndex.value( | 		state->manager.documentChanged(), | ||||||
| 		) | rpl::filter([=](int index) { |  | ||||||
| 			if (index >= state->shuffledDocuments.size()) { |  | ||||||
| 				state->next(); |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 			const auto id = state->shuffledDocuments[index]; |  | ||||||
| 			if (!controller->session().data().document(id)->sticker()) { |  | ||||||
| 				state->next(); |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 			return true; |  | ||||||
| 		}) | rpl::map([=](int index) { |  | ||||||
| 			return controller->session().data().customEmojiManager().resolve( |  | ||||||
| 				state->shuffledDocuments[index]); |  | ||||||
| 		}) | rpl::flatten_latest() | rpl::map([=](not_null<DocumentData*> d) { |  | ||||||
| 			state->documentShown(); |  | ||||||
| 			return d; |  | ||||||
| 		}), |  | ||||||
| 		state->colorIndex.value(), | 		state->colorIndex.value(), | ||||||
| 		isForum); | 		isForum); | ||||||
| 	icon->setAttribute(Qt::WA_TransparentForMouseEvents); | 	icon->setAttribute(Qt::WA_TransparentForMouseEvents); | ||||||
|  | @ -115,13 +204,7 @@ void AddEmojiBuilderAction( | ||||||
| 	rpl::duplicate( | 	rpl::duplicate( | ||||||
| 		documents | 		documents | ||||||
| 	) | rpl::start_with_next([=](std::vector<DocumentId> documents) { | 	) | rpl::start_with_next([=](std::vector<DocumentId> documents) { | ||||||
| 		if (documents.empty()) { | 		state->manager.setDocuments(std::move(documents)); | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		auto rd = std::random_device(); |  | ||||||
| 		ranges::shuffle(documents, std::mt19937(rd())); |  | ||||||
| 		state->shuffledDocuments = std::move(documents); |  | ||||||
| 		state->documentIndex.force_assign(0); |  | ||||||
| 	}, item->lifetime()); | 	}, item->lifetime()); | ||||||
| 
 | 
 | ||||||
| 	menu->addAction(std::move(item)); | 	menu->addAction(std::move(item)); | ||||||
|  |  | ||||||
|  | @ -419,7 +419,8 @@ not_null<Ui::VerticalLayout*> CreateUserpicBuilder( | ||||||
| 				data.isForum)), | 				data.isForum)), | ||||||
| 		st::userpicBuilderEmojiPreviewPadding)->entity(); | 		st::userpicBuilderEmojiPreviewPadding)->entity(); | ||||||
| 	if (const auto id = data.documentId) { | 	if (const auto id = data.documentId) { | ||||||
| 		if (const auto document = controller->session().data().document(id)) { | 		const auto document = controller->session().data().document(id); | ||||||
|  | 		if (document && document->sticker()) { | ||||||
| 			preview->setDocument(document); | 			preview->setDocument(document); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 23rd
						23rd