mirror of https://github.com/procxx/kepka.git
				
				
				
			Encapsulated inline bot result class. Started inline bot
result downloading by external links, not ready (at all).
This commit is contained in:
		
							parent
							
								
									1e72c8a89b
								
							
						
					
					
						commit
						3be34a4bb7
					
				|  | @ -832,6 +832,49 @@ private: | |||
| 
 | ||||
| }; | ||||
| 
 | ||||
| // This pointer is used for static non-POD variables that are allocated
 | ||||
| // on first use by constructor and are never automatically freed.
 | ||||
| template <typename T> | ||||
| class StaticNeverFreedPointer { | ||||
| public: | ||||
| 	explicit StaticNeverFreedPointer(T *p) : _p(p) { | ||||
| 	} | ||||
| 	StaticNeverFreedPointer(const StaticNeverFreedPointer<T> &other) = delete; | ||||
| 	StaticNeverFreedPointer &operator=(const StaticNeverFreedPointer<T> &other) = delete; | ||||
| 
 | ||||
| 	T *data() const { | ||||
| 		return _p; | ||||
| 	} | ||||
| 	T *release() { | ||||
| 		return getPointerAndReset(_p); | ||||
| 	} | ||||
| 	void reset(T *p = nullptr) { | ||||
| 		delete _p; | ||||
| 		_p = p; | ||||
| 	} | ||||
| 	bool isNull() const { | ||||
| 		return data() == nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	void clear() { | ||||
| 		reset(); | ||||
| 	} | ||||
| 	T *operator->() const { | ||||
| 		return data(); | ||||
| 	} | ||||
| 	T &operator*() const { | ||||
| 		t_assert(!isNull()); | ||||
| 		return *data(); | ||||
| 	} | ||||
| 	explicit operator bool() const { | ||||
| 		return !isNull(); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	T *_p = nullptr; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| template <typename I> | ||||
| inline void destroyImplementation(I *&ptr) { | ||||
| 	if (ptr) { | ||||
|  |  | |||
|  | @ -1458,82 +1458,25 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { | |||
| 		} | ||||
| 
 | ||||
| 		InlineItem *item = _inlineRows.at(row).items.at(col); | ||||
| 		PhotoData *photo = item->getPhoto(); | ||||
| 		DocumentData *document = item->getDocument(); | ||||
| 		InlineResult *inlineResult = item->getResult(); | ||||
| 		using Type = InlineResult::Type; | ||||
| 		auto getShownPhoto = [photo, inlineResult]() -> PhotoData* { | ||||
| 			if (photo) { | ||||
| 				return photo; | ||||
| 			} else if (inlineResult && inlineResult->type == Type::Photo) { | ||||
| 				return inlineResult->photo; | ||||
| 			} | ||||
| 			return nullptr; | ||||
| 		}; | ||||
| 		auto getShownDocument = [document, inlineResult]() -> DocumentData* { | ||||
| 			auto inlineResultIsFileType = [](InlineResult *inlineResult) { | ||||
| 				return inlineResult->type == Type::Video || | ||||
| 					inlineResult->type == Type::Audio || | ||||
| 					inlineResult->type == Type::Sticker || | ||||
| 					inlineResult->type == Type::File || | ||||
| 					inlineResult->type == Type::Gif; | ||||
| 			}; | ||||
| 			if (document) { | ||||
| 				return document; | ||||
| 			} else if (inlineResult && inlineResultIsFileType(inlineResult)) { | ||||
| 				return inlineResult->document; | ||||
| 			} | ||||
| 			return nullptr; | ||||
| 		}; | ||||
| 		auto sendInlineItem = [photo, document, inlineResult, this]() -> void { | ||||
| 			if (photo) { | ||||
| 		if (PhotoData *photo = item->getPhoto()) { | ||||
| 			if (photo->medium->loaded() || photo->thumb->loaded()) { | ||||
| 				emit selected(photo); | ||||
| 			} else if (document) { | ||||
| 			} else if (!photo->medium->loading()) { | ||||
| 				photo->thumb->loadEvenCancelled(); | ||||
| 				photo->medium->loadEvenCancelled(); | ||||
| 			} | ||||
| 		} else if (DocumentData *document = item->getDocument()) { | ||||
| 			if (document->loaded()) { | ||||
| 				emit selected(document); | ||||
| 			} else if (inlineResult) { | ||||
| 			} else if (document->loading()) { | ||||
| 				document->cancel(); | ||||
| 			} else { | ||||
| 				DocumentOpenClickHandler::doOpen(document, ActionOnLoadNone); | ||||
| 			} | ||||
| 		} else if (InlineResult *inlineResult = item->getResult()) { | ||||
| 			if (inlineResult->onChoose(item)) { | ||||
| 				emit selected(inlineResult, _inlineBot); | ||||
| 			} | ||||
| 		}; | ||||
| 		if (PhotoData *shownPhoto = getShownPhoto()) { | ||||
| 			if (shownPhoto->medium->loaded() || shownPhoto->thumb->loaded()) { | ||||
| 				sendInlineItem(); | ||||
| 			} else if (!shownPhoto->medium->loading()) { | ||||
| 				shownPhoto->thumb->loadEvenCancelled(); | ||||
| 				shownPhoto->medium->loadEvenCancelled(); | ||||
| 			} | ||||
| 		} else if (DocumentData *shownDocument = getShownDocument()) { | ||||
| 			if (!inlineResult || inlineResult->type == Type::Gif) { | ||||
| 				if (shownDocument->loaded()) { | ||||
| 					sendInlineItem(); | ||||
| 				} else if (shownDocument->loading()) { | ||||
| 					shownDocument->cancel(); | ||||
| 				} else { | ||||
| 					DocumentOpenClickHandler::doOpen(shownDocument, ActionOnLoadNone); | ||||
| 				} | ||||
| 			} else { | ||||
| 				sendInlineItem(); | ||||
| 			} | ||||
| 		} else if (inlineResult) { | ||||
| 			if (inlineResult->type == Type::Photo) { | ||||
| 				if (inlineResult->thumb->loaded()) { | ||||
| 					sendInlineItem(); | ||||
| 				} else if (!inlineResult->thumb->loading()) { | ||||
| 					inlineResult->thumb->loadEvenCancelled(); | ||||
| 					Ui::repaintInlineItem(item); | ||||
| 				} | ||||
| 			} else if (inlineResult->type == Type::Gif) { | ||||
| 				if (inlineResult->loaded()) { | ||||
| 					sendInlineItem(); | ||||
| 				} else if (inlineResult->loading()) { | ||||
| 					inlineResult->cancelFile(); | ||||
| 					Ui::repaintInlineItem(item); | ||||
| 				} else { | ||||
| 					inlineResult->saveFile(QString(), LoadFromCloudOrLocal, false); | ||||
| 					Ui::repaintInlineItem(item); | ||||
| 				} | ||||
| 			} else { | ||||
| 				sendInlineItem(); | ||||
| 			} | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
|  | @ -1655,12 +1598,7 @@ void StickerPanInner::hideFinish(bool completely) { | |||
| 				photo->forget(); | ||||
| 			} | ||||
| 			if (InlineResult *result = item->getResult()) { | ||||
| 				if (DocumentData *document = result->document) { | ||||
| 					document->forget(); | ||||
| 				} | ||||
| 				if (PhotoData *photo = result->photo) { | ||||
| 					photo->forget(); | ||||
| 				} | ||||
| 				result->forget(); | ||||
| 			} | ||||
| 		}; | ||||
| 		clearInlineRows(false); | ||||
|  |  | |||
|  | @ -6775,7 +6775,7 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot | |||
| 
 | ||||
| 	result->addToHistory(_history, flags, messageId, messageFromId, messageDate, messageViaBotId, replyToId()); | ||||
| 
 | ||||
| 	_history->sendRequestId = MTP::send(MTPmessages_SendInlineBotResult(MTP_flags(sendFlags), _peer->input, MTP_int(replyToId()), MTP_long(randomId), MTP_long(result->queryId), MTP_string(result->id)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId); | ||||
| 	_history->sendRequestId = MTP::send(MTPmessages_SendInlineBotResult(MTP_flags(sendFlags), _peer->input, MTP_int(replyToId()), MTP_long(randomId), MTP_long(result->getQueryId()), MTP_string(result->getId())), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId); | ||||
| 	App::main()->finishForwarding(_history, _broadcast.checked(), _silent.checked()); | ||||
| 	cancelReply(lastKeyboardUsed); | ||||
| 
 | ||||
|  |  | |||
|  | @ -38,10 +38,8 @@ FileBase::FileBase(DocumentData *document) : ItemBase(document) { | |||
| DocumentData *FileBase::getShownDocument() const { | ||||
| 	if (DocumentData *result = getDocument()) { | ||||
| 		return result; | ||||
| 	} else if (Result *result = getResult()) { | ||||
| 		return result->document; | ||||
| 	} | ||||
| 	return nullptr; | ||||
| 	return getResultDocument(); | ||||
| } | ||||
| 
 | ||||
| int FileBase::content_width() const { | ||||
|  | @ -52,10 +50,8 @@ int FileBase::content_width() const { | |||
| 		if (!document->thumb->isNull()) { | ||||
| 			return convertScale(document->thumb->width()); | ||||
| 		} | ||||
| 	} else if (_result) { | ||||
| 		return _result->width; | ||||
| 	} | ||||
| 	return 0; | ||||
| 	return getResultWidth(); | ||||
| } | ||||
| 
 | ||||
| int FileBase::content_height() const { | ||||
|  | @ -66,10 +62,8 @@ int FileBase::content_height() const { | |||
| 		if (!document->thumb->isNull()) { | ||||
| 			return convertScale(document->thumb->height()); | ||||
| 		} | ||||
| 	} else if (_result) { | ||||
| 		return _result->height; | ||||
| 	} | ||||
| 	return 0; | ||||
| 	return getResultHeight(); | ||||
| } | ||||
| 
 | ||||
| bool FileBase::content_loading() const { | ||||
|  | @ -136,23 +130,20 @@ ImagePtr FileBase::content_thumb() const { | |||
| 			return document->thumb; | ||||
| 		} | ||||
| 	} | ||||
| 	if (_result->photo && !_result->photo->thumb->isNull()) { | ||||
| 		return _result->photo->thumb; | ||||
| 	} | ||||
| 	return _result->thumb; | ||||
| 	return getResultThumb(); | ||||
| } | ||||
| 
 | ||||
| int FileBase::content_duration() const { | ||||
| 	if (_result->document) { | ||||
| 		if (_result->document->duration() > 0) { | ||||
| 			return _result->document->duration(); | ||||
| 		} else if (SongData *song = _result->document->song()) { | ||||
| 	if (DocumentData *document = getShownDocument()) { | ||||
| 		if (document->duration() > 0) { | ||||
| 			return document->duration(); | ||||
| 		} else if (SongData *song = document->song()) { | ||||
| 			if (song->duration) { | ||||
| 				return song->duration; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return _result->duration; | ||||
| 	return getResultDuration(); | ||||
| } | ||||
| 
 | ||||
| Gif::Gif(Result *result) : FileBase(result) { | ||||
|  | @ -354,13 +345,14 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const { | |||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (!_result->thumb_url.isEmpty()) { | ||||
| 			if (_result->thumb->loaded()) { | ||||
| 		ImagePtr thumb = getResultThumb(); | ||||
| 		if (!thumb->isNull()) { | ||||
| 			if (thumb->loaded()) { | ||||
| 				if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { | ||||
| 					_thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); | ||||
| 					_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); | ||||
| 				} | ||||
| 			} else { | ||||
| 				_result->thumb->load(); | ||||
| 				thumb->load(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -437,8 +429,11 @@ void Sticker::preload() const { | |||
| 		} else { | ||||
| 			document->checkSticker(); | ||||
| 		} | ||||
| 	} else if (!_result->thumb->isNull()) { | ||||
| 		_result->thumb->load(); | ||||
| 	} else { | ||||
| 		ImagePtr thumb = getResultThumb(); | ||||
| 		if (!thumb->isNull()) { | ||||
| 			thumb->load(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -506,14 +501,15 @@ void Sticker::prepareThumb() const { | |||
| 			_thumbLoaded = true; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (_result->thumb->loaded()) { | ||||
| 		ImagePtr thumb = getResultThumb(); | ||||
| 		if (thumb->loaded()) { | ||||
| 			if (!_thumbLoaded) { | ||||
| 				QSize thumbSize = getThumbSize(); | ||||
| 				_thumb = _result->thumb->pix(thumbSize.width(), thumbSize.height()); | ||||
| 				_thumb = thumb->pix(thumbSize.width(), thumbSize.height()); | ||||
| 				_thumbLoaded = true; | ||||
| 			} | ||||
| 		} else { | ||||
| 			_result->thumb->load(); | ||||
| 			thumb->load(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -557,10 +553,8 @@ void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, | |||
| PhotoData *Photo::getShownPhoto() const { | ||||
| 	if (PhotoData *result = getPhoto()) { | ||||
| 		return result; | ||||
| 	} else if (Result *result = getResult()) { | ||||
| 		return result->photo; | ||||
| 	} | ||||
| 	return nullptr; | ||||
| 	return getResultPhoto(); | ||||
| } | ||||
| 
 | ||||
| QSize Photo::countFrameSize() const { | ||||
|  | @ -605,12 +599,13 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const { | |||
| 			photo->medium->load(); | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (_result->thumb->loaded()) { | ||||
| 		ImagePtr thumb = getResultThumb(); | ||||
| 		if (thumb->loaded()) { | ||||
| 			if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { | ||||
| 				_thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); | ||||
| 				_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); | ||||
| 			} | ||||
| 		} else { | ||||
| 			_result->thumb->load(); | ||||
| 			thumb->load(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -618,19 +613,15 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const { | |||
| int Photo::content_width() const { | ||||
| 	if (PhotoData *photo = getShownPhoto()) { | ||||
| 		return photo->full->width(); | ||||
| 	} else if (_result) { | ||||
| 		return _result->width; | ||||
| 	} | ||||
| 	return 0; | ||||
| 	return getResultWidth(); | ||||
| } | ||||
| 
 | ||||
| int Photo::content_height() const { | ||||
| 	if (PhotoData *photo = getShownPhoto()) { | ||||
| 		return photo->full->height(); | ||||
| 	} else if (_result) { | ||||
| 		return _result->height; | ||||
| 	} | ||||
| 	return 0; | ||||
| 	return getResultHeight(); | ||||
| } | ||||
| 
 | ||||
| bool Photo::content_loaded() const { | ||||
|  | @ -649,11 +640,9 @@ void Photo::content_forget() { | |||
| } | ||||
| 
 | ||||
| Video::Video(Result *result) : FileBase(result) | ||||
| , _link(getResultContentUrlHandler()) | ||||
| , _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) | ||||
| , _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) { | ||||
| 	if (!result->content_url.isEmpty()) { | ||||
| 		_link = clickHandlerFromUrl(result->content_url); | ||||
| 	} | ||||
| 	if (int duration = content_duration()) { | ||||
| 		_duration = formatDurationText(duration); | ||||
| 	} | ||||
|  | @ -749,7 +738,7 @@ void Video::prepareThumb(int32 width, int32 height) const { | |||
| } | ||||
| 
 | ||||
| void OpenFileClickHandler::onClickImpl() const { | ||||
| 	_result->automaticLoadGif(); | ||||
| 	_result->openFile(); | ||||
| } | ||||
| 
 | ||||
| void CancelFileClickHandler::onClickImpl() const { | ||||
|  | @ -907,52 +896,23 @@ void File::checkAnimationFinished() { | |||
| } | ||||
| 
 | ||||
| Article::Article(Result *result, bool withThumb) : ItemBase(result) | ||||
| , _url(getResultUrlHandler()) | ||||
| , _link(getResultContentUrlHandler()) | ||||
| , _withThumb(withThumb) | ||||
| , _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) | ||||
| , _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) { | ||||
| 	if (!result->url.isEmpty()) { | ||||
| 		_url = clickHandlerFromUrl(result->url); | ||||
| 	} | ||||
| 	if (!result->content_url.isEmpty()) { | ||||
| 		_link = clickHandlerFromUrl(result->content_url); | ||||
| 	} else { | ||||
| 	LocationCoords location; | ||||
| 		if (result->getLocationCoords(&location)) { | ||||
| 	if (!_link && result->getLocationCoords(&location)) { | ||||
| 		_link.reset(new LocationClickHandler(location)); | ||||
| 			int32 w = st::inlineThumbSize, h = st::inlineThumbSize; | ||||
| 			int32 zoom = 13, scale = 1; | ||||
| 			if (cScale() == dbisTwo || cRetina()) { | ||||
| 				scale = 2; | ||||
| 				w /= 2; | ||||
| 				h /= 2; | ||||
| 			} | ||||
| 			QString coords = qsl("%1,%2").arg(location.lat).arg(location.lon); | ||||
| 			QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false"); | ||||
| 			result->thumb = ImagePtr(url); | ||||
| 		} | ||||
| 	} | ||||
| 	QVector<QStringRef> parts = _result->url.splitRef('/'); | ||||
| 	if (!parts.isEmpty()) { | ||||
| 		QStringRef domain = parts.at(0); | ||||
| 		if (parts.size() > 2 && domain.endsWith(':') && parts.at(1).isEmpty()) { // http:// and others
 | ||||
| 			domain = parts.at(2); | ||||
| 		} | ||||
| 
 | ||||
| 		parts = domain.split('@').back().split('.'); | ||||
| 		if (parts.size() > 1) { | ||||
| 			_letter = parts.at(parts.size() - 2).at(0).toUpper(); | ||||
| 		} | ||||
| 	} | ||||
| 	if (_letter.isEmpty() && !_result->title.isEmpty()) { | ||||
| 		_letter = _result->title.at(0).toUpper(); | ||||
| 	} | ||||
| 	_thumbLetter = getResultThumbLetter(); | ||||
| } | ||||
| 
 | ||||
| void Article::initDimensions() { | ||||
| 	_maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft; | ||||
| 	int32 textWidth = _maxw - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0); | ||||
| 	TextParseOptions titleOpts = { 0, _maxw, 2 * st::semiboldFont->height, Qt::LayoutDirectionAuto }; | ||||
| 	_title.setText(st::semiboldFont, textOneLine(_result->title), titleOpts); | ||||
| 	_title.setText(st::semiboldFont, textOneLine(_result->getLayoutTitle()), titleOpts); | ||||
| 	int32 titleHeight = qMin(_title.countHeight(_maxw), 2 * st::semiboldFont->height); | ||||
| 
 | ||||
| 	int32 descriptionLines = (_withThumb || _url) ? 2 : 3; | ||||
|  | @ -970,10 +930,10 @@ void Article::initDimensions() { | |||
| int32 Article::resizeGetHeight(int32 width) { | ||||
| 	_width = qMin(width, _maxw); | ||||
| 	if (_url) { | ||||
| 		_urlText = _result->url; | ||||
| 		_urlText = getResultUrl(); | ||||
| 		_urlWidth = st::normalFont->width(_urlText); | ||||
| 		if (_urlWidth > _width - st::inlineThumbSize - st::inlineThumbSkip) { | ||||
| 			_urlText = st::normalFont->elided(_result->url, _width - st::inlineThumbSize - st::inlineThumbSkip); | ||||
| 			_urlText = st::normalFont->elided(_urlText, _width - st::inlineThumbSize - st::inlineThumbSkip); | ||||
| 			_urlWidth = st::normalFont->width(_urlText); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -988,15 +948,16 @@ void Article::paint(Painter &p, const QRect &clip, uint32 selection, const Paint | |||
| 		prepareThumb(st::inlineThumbSize, st::inlineThumbSize); | ||||
| 		QRect rthumb(rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width)); | ||||
| 		if (_thumb.isNull()) { | ||||
| 			if (_result->thumb->isNull() && !_letter.isEmpty()) { | ||||
| 				int32 index = (_letter.at(0).unicode() % 4); | ||||
| 			ImagePtr thumb = getResultThumb(); | ||||
| 			if (thumb->isNull() && !_thumbLetter.isEmpty()) { | ||||
| 				int32 index = (_thumbLetter.at(0).unicode() % 4); | ||||
| 				style::color colors[] = { st::msgFileRedColor, st::msgFileYellowColor, st::msgFileGreenColor, st::msgFileBlueColor }; | ||||
| 
 | ||||
| 				p.fillRect(rthumb, colors[index]); | ||||
| 				if (!_letter.isEmpty()) { | ||||
| 				if (!_thumbLetter.isEmpty()) { | ||||
| 					p.setFont(st::linksLetterFont); | ||||
| 					p.setPen(st::white); | ||||
| 					p.drawText(rthumb, _letter, style::al_center); | ||||
| 					p.drawText(rthumb, _thumbLetter, style::al_center); | ||||
| 				} | ||||
| 			} else { | ||||
| 				p.fillRect(rthumb, st::overviewPhotoBg); | ||||
|  | @ -1047,18 +1008,17 @@ void Article::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 | |||
| } | ||||
| 
 | ||||
| void Article::prepareThumb(int32 width, int32 height) const { | ||||
| 	if (_result->thumb->isNull()) { | ||||
| 		if (_result->type == Result::Type::Contact) { | ||||
| 	ImagePtr thumb = getResultThumb(); | ||||
| 	if (thumb->isNull()) { | ||||
| 		if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { | ||||
| 				_thumb = userDefPhoto(qHash(_result->id) % UserColorsCount)->pixCircled(width, height); | ||||
| 			} | ||||
| 			_thumb = getResultContactAvatar(width, height); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (_result->thumb->loaded()) { | ||||
| 	if (thumb->loaded()) { | ||||
| 		if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { | ||||
| 			int32 w = qMax(convertScale(_result->thumb->width()), 1), h = qMax(convertScale(_result->thumb->height()), 1); | ||||
| 			int32 w = qMax(convertScale(thumb->width()), 1), h = qMax(convertScale(thumb->height()), 1); | ||||
| 			if (w * height > h * width) { | ||||
| 				if (height < h) { | ||||
| 					w = w * height / h; | ||||
|  | @ -1070,10 +1030,10 @@ void Article::prepareThumb(int32 width, int32 height) const { | |||
| 					w = width; | ||||
| 				} | ||||
| 			} | ||||
| 			_thumb = _result->thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); | ||||
| 			_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); | ||||
| 		} | ||||
| 	} else { | ||||
| 		_result->thumb->load(); | ||||
| 		thumb->load(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -313,7 +313,7 @@ private: | |||
| 	bool _withThumb; | ||||
| 	mutable QPixmap _thumb; | ||||
| 	Text _title, _description; | ||||
| 	QString _letter, _urlText; | ||||
| 	QString _thumbLetter, _urlText; | ||||
| 	int32 _urlWidth; | ||||
| 
 | ||||
| 	void prepareThumb(int32 width, int32 height) const; | ||||
|  |  | |||
|  | @ -51,12 +51,12 @@ PhotoData *ItemBase::getPhoto() const { | |||
| 
 | ||||
| void ItemBase::preload() const { | ||||
| 	if (_result) { | ||||
| 		if (_result->photo) { | ||||
| 			_result->photo->thumb->load(); | ||||
| 		} else if (_result->document) { | ||||
| 			_result->document->thumb->load(); | ||||
| 		} else if (!_result->thumb->isNull()) { | ||||
| 			_result->thumb->load(); | ||||
| 		if (_result->_photo) { | ||||
| 			_result->_photo->thumb->load(); | ||||
| 		} else if (_result->_document) { | ||||
| 			_result->_document->thumb->load(); | ||||
| 		} else if (!_result->_thumb->isNull()) { | ||||
| 			_result->_thumb->load(); | ||||
| 		} | ||||
| 	} else if (_doc) { | ||||
| 		_doc->thumb->load(); | ||||
|  | @ -74,7 +74,7 @@ void ItemBase::update() { | |||
| UniquePointer<ItemBase> ItemBase::createLayout(Result *result, bool forceThumb) { | ||||
| 	using Type = Result::Type; | ||||
| 
 | ||||
| 	switch (result->type) { | ||||
| 	switch (result->_type) { | ||||
| 	case Type::Photo: return MakeUnique<internal::Photo>(result); break; | ||||
| 	case Type::Audio: | ||||
| 	case Type::File: return MakeUnique<internal::File>(result); break; | ||||
|  | @ -92,5 +92,82 @@ UniquePointer<ItemBase> ItemBase::createLayoutGif(DocumentData *document) { | |||
| 	return MakeUnique<internal::Gif>(document, true); | ||||
| } | ||||
| 
 | ||||
| DocumentData *ItemBase::getResultDocument() const { | ||||
| 	return _result ? _result->_document : nullptr; | ||||
| } | ||||
| 
 | ||||
| PhotoData *ItemBase::getResultPhoto() const { | ||||
| 	return _result ? _result->_photo : nullptr; | ||||
| } | ||||
| 
 | ||||
| int ItemBase::getResultWidth() const { | ||||
| 	return _result ? _result->_width : 0; | ||||
| } | ||||
| 
 | ||||
| int ItemBase::getResultHeight() const { | ||||
| 	return _result ? _result->_height : 0; | ||||
| } | ||||
| 
 | ||||
| ImagePtr ItemBase::getResultThumb() const { | ||||
| 	if (_result) { | ||||
| 		if (_result->_photo && !_result->_photo->thumb->isNull()) { | ||||
| 			return _result->_photo->thumb; | ||||
| 		} | ||||
| 		if (!_result->_thumb->isNull()) { | ||||
| 			return _result->_thumb; | ||||
| 		} | ||||
| 		return _result->_locationThumb; | ||||
| 	} | ||||
| 	return ImagePtr(); | ||||
| } | ||||
| 
 | ||||
| QPixmap ItemBase::getResultContactAvatar(int width, int height) const { | ||||
| 	if (_result->_type == Result::Type::Contact) { | ||||
| 		return userDefPhoto(qHash(_result->_id) % UserColorsCount)->pixCircled(width, height); | ||||
| 	} | ||||
| 	return QPixmap(); | ||||
| } | ||||
| 
 | ||||
| int ItemBase::getResultDuration() const { | ||||
| 	return _result->_duration; | ||||
| } | ||||
| 
 | ||||
| QString ItemBase::getResultUrl() const { | ||||
| 	return _result->_url; | ||||
| } | ||||
| 
 | ||||
| ClickHandlerPtr ItemBase::getResultUrlHandler() const { | ||||
| 	if (!_result->_url.isEmpty()) { | ||||
| 		return clickHandlerFromUrl(_result->_url); | ||||
| 	} | ||||
| 	return ClickHandlerPtr(); | ||||
| } | ||||
| 
 | ||||
| ClickHandlerPtr ItemBase::getResultContentUrlHandler() const { | ||||
| 	if (!_result->_content_url.isEmpty()) { | ||||
| 		return clickHandlerFromUrl(_result->_content_url); | ||||
| 	} | ||||
| 	return ClickHandlerPtr(); | ||||
| } | ||||
| 
 | ||||
| QString ItemBase::getResultThumbLetter() const { | ||||
| 	QVector<QStringRef> parts = _result->_url.splitRef('/'); | ||||
| 	if (!parts.isEmpty()) { | ||||
| 		QStringRef domain = parts.at(0); | ||||
| 		if (parts.size() > 2 && domain.endsWith(':') && parts.at(1).isEmpty()) { // http:// and others
 | ||||
| 			domain = parts.at(2); | ||||
| 		} | ||||
| 
 | ||||
| 		parts = domain.split('@').back().split('.'); | ||||
| 		if (parts.size() > 1) { | ||||
| 			return parts.at(parts.size() - 2).at(0).toUpper(); | ||||
| 		} | ||||
| 	} | ||||
| 	if (!_result->_title.isEmpty()) { | ||||
| 		return _result->_title.at(0).toUpper(); | ||||
| 	} | ||||
| 	return QString(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Layout
 | ||||
| } // namespace InlineBots
 | ||||
|  |  | |||
|  | @ -89,6 +89,18 @@ public: | |||
| 	static UniquePointer<ItemBase> createLayoutGif(DocumentData *document); | ||||
| 
 | ||||
| protected: | ||||
| 	DocumentData *getResultDocument() const; | ||||
| 	PhotoData *getResultPhoto() const; | ||||
| 	int getResultWidth() const; | ||||
| 	int getResultHeight() const; | ||||
| 	ImagePtr getResultThumb() const; | ||||
| 	QPixmap getResultContactAvatar(int width, int height) const; | ||||
| 	int getResultDuration() const; | ||||
| 	QString getResultUrl() const; | ||||
| 	ClickHandlerPtr getResultUrlHandler() const; | ||||
| 	ClickHandlerPtr getResultContentUrlHandler() const; | ||||
| 	QString getResultThumbLetter() const; | ||||
| 
 | ||||
| 	Result *_result = nullptr; | ||||
| 	DocumentData *_doc = nullptr; | ||||
| 	PhotoData *_photo = nullptr; | ||||
|  |  | |||
|  | @ -56,18 +56,12 @@ Result *getResultFromLoader(FileLoader *loader) { | |||
| 	return ResultsByLoader->value(loader, nullptr); | ||||
| } | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| using StringToTypeMap = QMap<QString, Result::Type>; | ||||
| NeverFreedPointer<StringToTypeMap> stringToTypeMap; | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| Result::Result(const Creator &creator) : queryId(creator.queryId), type(creator.type) { | ||||
| Result::Result(const Creator &creator) : _queryId(creator.queryId), _type(creator.type) { | ||||
| } | ||||
| 
 | ||||
| UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) { | ||||
| 	stringToTypeMap.createIfNull([]() -> StringToTypeMap* { | ||||
| 	using StringToTypeMap = QMap<QString, Result::Type>; | ||||
| 	StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* { | ||||
| 		auto result = MakeUnique<StringToTypeMap>(); | ||||
| 		result->insert(qsl("photo"), Result::Type::Photo); | ||||
| 		result->insert(qsl("video"), Result::Type::Video); | ||||
|  | @ -79,8 +73,9 @@ UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &m | |||
| 		result->insert(qsl("contact"), Result::Type::Contact); | ||||
| 		result->insert(qsl("venue"), Result::Type::Venue); | ||||
| 		return result.release(); | ||||
| 	}); | ||||
| 	auto getInlineResultType = [](const MTPBotInlineResult &inlineResult) -> Type { | ||||
| 	})() }; | ||||
| 
 | ||||
| 	auto getInlineResultType = [&stringToTypeMap](const MTPBotInlineResult &inlineResult) -> Type { | ||||
| 		QString type; | ||||
| 		switch (inlineResult.type()) { | ||||
| 		case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break; | ||||
|  | @ -98,32 +93,38 @@ UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &m | |||
| 	switch (mtpData.type()) { | ||||
| 	case mtpc_botInlineResult: { | ||||
| 		const MTPDbotInlineResult &r(mtpData.c_botInlineResult()); | ||||
| 		result->id = qs(r.vid); | ||||
| 		if (r.has_title()) result->title = qs(r.vtitle); | ||||
| 		if (r.has_description()) result->description = qs(r.vdescription); | ||||
| 		if (r.has_url()) result->url = qs(r.vurl); | ||||
| 		if (r.has_thumb_url()) result->thumb_url = qs(r.vthumb_url); | ||||
| 		if (r.has_content_type()) result->content_type = qs(r.vcontent_type); | ||||
| 		if (r.has_content_url()) result->content_url = qs(r.vcontent_url); | ||||
| 		if (r.has_w()) result->width = r.vw.v; | ||||
| 		if (r.has_h()) result->height = r.vh.v; | ||||
| 		if (r.has_duration()) result->duration = r.vduration.v; | ||||
| 		if (!result->thumb_url.isEmpty() && (result->thumb_url.startsWith(qstr("http://"), Qt::CaseInsensitive) || result->thumb_url.startsWith(qstr("https://"), Qt::CaseInsensitive))) { | ||||
| 			result->thumb = ImagePtr(result->thumb_url); | ||||
| 		result->_id = qs(r.vid); | ||||
| 		if (r.has_title()) result->_title = qs(r.vtitle); | ||||
| 		if (r.has_description()) result->_description = qs(r.vdescription); | ||||
| 		if (r.has_url()) result->_url = qs(r.vurl); | ||||
| 		if (r.has_thumb_url()) result->_thumb_url = qs(r.vthumb_url); | ||||
| 		if (r.has_content_type()) result->_content_type = qs(r.vcontent_type); | ||||
| 		if (r.has_content_url()) result->_content_url = qs(r.vcontent_url); | ||||
| 		if (r.has_w()) result->_width = r.vw.v; | ||||
| 		if (r.has_h()) result->_height = r.vh.v; | ||||
| 		if (r.has_duration()) result->_duration = r.vduration.v; | ||||
| 		if (!result->_thumb_url.isEmpty() && (result->_thumb_url.startsWith(qstr("http://"), Qt::CaseInsensitive) || result->_thumb_url.startsWith(qstr("https://"), Qt::CaseInsensitive))) { | ||||
| 			result->_thumb = ImagePtr(result->_thumb_url); | ||||
| 		} | ||||
| 		message = &r.vsend_message; | ||||
| 	} break; | ||||
| 	case mtpc_botInlineMediaResult: { | ||||
| 		const MTPDbotInlineMediaResult &r(mtpData.c_botInlineMediaResult()); | ||||
| 		result->id = qs(r.vid); | ||||
| 		if (r.has_title()) result->title = qs(r.vtitle); | ||||
| 		if (r.has_description()) result->description = qs(r.vdescription); | ||||
| 		if (r.has_photo()) result->photo = App::feedPhoto(r.vphoto); | ||||
| 		if (r.has_document()) result->document = App::feedDocument(r.vdocument); | ||||
| 		result->_id = qs(r.vid); | ||||
| 		if (r.has_title()) result->_title = qs(r.vtitle); | ||||
| 		if (r.has_description()) result->_description = qs(r.vdescription); | ||||
| 		if (r.has_photo()) { | ||||
| 			result->_mtpPhoto = r.vphoto; | ||||
| 			result->_photo = App::feedPhoto(r.vphoto); | ||||
| 		} | ||||
| 		if (r.has_document()) { | ||||
| 			result->_mtpDocument = r.vdocument; | ||||
| 			result->_document = App::feedDocument(r.vdocument); | ||||
| 		} | ||||
| 		message = &r.vsend_message; | ||||
| 	} break; | ||||
| 	} | ||||
| 	bool badAttachment = (result->photo && !result->photo->access) || (result->document && !result->document->access); | ||||
| 	bool badAttachment = (result->_photo && !result->_photo->access) || (result->_document && !result->_document->access); | ||||
| 
 | ||||
| 	if (!message) { | ||||
| 		return UniquePointer<Result>(); | ||||
|  | @ -132,10 +133,10 @@ UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &m | |||
| 	switch (message->type()) { | ||||
| 	case mtpc_botInlineMessageMediaAuto: { | ||||
| 		const MTPDbotInlineMessageMediaAuto &r(message->c_botInlineMessageMediaAuto()); | ||||
| 		if (result->type == Type::Photo) { | ||||
| 			result->sendData.reset(new internal::SendPhoto(result->photo, result->content_url, qs(r.vcaption))); | ||||
| 		if (result->_type == Type::Photo) { | ||||
| 			result->sendData.reset(new internal::SendPhoto(result->_photo, result->_content_url, qs(r.vcaption))); | ||||
| 		} else { | ||||
| 			result->sendData.reset(new internal::SendFile(result->document, result->content_url, qs(r.vcaption))); | ||||
| 			result->sendData.reset(new internal::SendFile(result->_document, result->_content_url, qs(r.vcaption))); | ||||
| 		} | ||||
| 	} break; | ||||
| 
 | ||||
|  | @ -176,11 +177,81 @@ UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &m | |||
| 	if (badAttachment || !result->sendData || !result->sendData->isValid()) { | ||||
| 		return UniquePointer<Result>(); | ||||
| 	} | ||||
| 
 | ||||
| 	LocationCoords location; | ||||
| 	if (result->getLocationCoords(&location)) { | ||||
| 		int32 w = st::inlineThumbSize, h = st::inlineThumbSize; | ||||
| 		int32 zoom = 13, scale = 1; | ||||
| 		if (cScale() == dbisTwo || cRetina()) { | ||||
| 			scale = 2; | ||||
| 			w /= 2; | ||||
| 			h /= 2; | ||||
| 		} | ||||
| 		QString coords = qsl("%1,%2").arg(location.lat).arg(location.lon); | ||||
| 		QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false"); | ||||
| 		result->_locationThumb = ImagePtr(url); | ||||
| 	} | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| bool Result::onChoose(Layout::ItemBase *layout) { | ||||
| 	if (_photo && _type == Type::Photo) { | ||||
| 		if (_photo->medium->loaded() || _photo->thumb->loaded()) { | ||||
| 			return true; | ||||
| 		} else if (!_photo->medium->loading()) { | ||||
| 			_photo->thumb->loadEvenCancelled(); | ||||
| 			_photo->medium->loadEvenCancelled(); | ||||
| 		} | ||||
| 	} | ||||
| 	if (_document && ( | ||||
| 		_type == Type::Video || | ||||
| 		_type == Type::Audio || | ||||
| 		_type == Type::Sticker || | ||||
| 		_type == Type::File || | ||||
| 		_type == Type::Gif)) { | ||||
| 		if (_type == Type::Gif) { | ||||
| 			if (_document->loaded()) { | ||||
| 				return true; | ||||
| 			} else if (_document->loading()) { | ||||
| 				_document->cancel(); | ||||
| 			} else { | ||||
| 				DocumentOpenClickHandler::doOpen(_document, ActionOnLoadNone); | ||||
| 			} | ||||
| 		} else { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 	if (_type == Type::Photo) { | ||||
| 		if (_thumb->loaded()) { | ||||
| 			return true; | ||||
| 		} else if (!_thumb->loading()) { | ||||
| 			_thumb->loadEvenCancelled(); | ||||
| 			Ui::repaintInlineItem(layout); | ||||
| 		} | ||||
| 	} else if (_type == Type::Gif) { | ||||
| 		if (loaded()) { | ||||
| 			return true; | ||||
| 		} else if (loading()) { | ||||
| 			cancelFile(); | ||||
| 			Ui::repaintInlineItem(layout); | ||||
| 		} else { | ||||
| 			saveFile(QString(), LoadFromCloudOrLocal, false); | ||||
| 			Ui::repaintInlineItem(layout); | ||||
| 		} | ||||
| 	} else { | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void Result::automaticLoadGif() { | ||||
| 	if (loaded() || type != Type::Gif || (content_type != qstr("video/mp4") && content_type != "image/gif")) return; | ||||
| 	if (loaded() || _type != Type::Gif) { | ||||
| 		return; | ||||
| 	} | ||||
| 	if (_content_type != qstr("video/mp4") && _content_type != qstr("image/gif")) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (_loader != CancelledWebFileLoader) { | ||||
| 		// if load at least anywhere
 | ||||
|  | @ -191,7 +262,7 @@ void Result::automaticLoadGif() { | |||
| 
 | ||||
| void Result::automaticLoadSettingsChangedGif() { | ||||
| 	if (loaded() || _loader != CancelledWebFileLoader) return; | ||||
| 	_loader = 0; | ||||
| 	_loader = nullptr; | ||||
| } | ||||
| 
 | ||||
| void Result::saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading) { | ||||
|  | @ -199,18 +270,18 @@ void Result::saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, boo | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (_loader == CancelledWebFileLoader) _loader = 0; | ||||
| 	if (_loader == CancelledWebFileLoader) _loader = nullptr; | ||||
| 	if (_loader) { | ||||
| 		if (!_loader->setFileName(toFile)) { | ||||
| 			cancelFile(); | ||||
| 			_loader = 0; | ||||
| 			_loader = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (_loader) { | ||||
| 		if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud(); | ||||
| 	} else { | ||||
| 		_loader = new webFileLoader(content_url, toFile, fromCloud, autoLoading); | ||||
| 		_loader = new webFileLoader(_content_url, toFile, fromCloud, autoLoading); | ||||
| 		regLoader(_loader, this); | ||||
| 
 | ||||
| 		_loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(inlineResultLoadProgress(FileLoader*))); | ||||
|  | @ -219,6 +290,80 @@ void Result::saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, boo | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Result::openFile() { | ||||
| 	//if (loaded()) {
 | ||||
| 	//	bool playVoice = data->voice() && audioPlayer() && item;
 | ||||
| 	//	bool playMusic = data->song() && audioPlayer() && item;
 | ||||
| 	//	bool playAnimation = data->isAnimation() && item && item->getMedia();
 | ||||
| 	//	const FileLocation &location(data->location(true));
 | ||||
| 	//	if (!location.isEmpty() || (!data->data().isEmpty() && (playVoice || playMusic || playAnimation))) {
 | ||||
| 	//		if (playVoice) {
 | ||||
| 	//			AudioMsgId playing;
 | ||||
| 	//			AudioPlayerState playingState = AudioPlayerStopped;
 | ||||
| 	//			audioPlayer()->currentState(&playing, &playingState);
 | ||||
| 	//			if (playing.msgId == item->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
 | ||||
| 	//				audioPlayer()->pauseresume(OverviewVoiceFiles);
 | ||||
| 	//			} else {
 | ||||
| 	//				AudioMsgId audio(data, item->fullId());
 | ||||
| 	//				audioPlayer()->play(audio);
 | ||||
| 	//				if (App::main()) {
 | ||||
| 	//					App::main()->audioPlayProgress(audio);
 | ||||
| 	//					App::main()->mediaMarkRead(data);
 | ||||
| 	//				}
 | ||||
| 	//			}
 | ||||
| 	//		} else if (playMusic) {
 | ||||
| 	//			SongMsgId playing;
 | ||||
| 	//			AudioPlayerState playingState = AudioPlayerStopped;
 | ||||
| 	//			audioPlayer()->currentState(&playing, &playingState);
 | ||||
| 	//			if (playing.msgId == item->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
 | ||||
| 	//				audioPlayer()->pauseresume(OverviewFiles);
 | ||||
| 	//			} else {
 | ||||
| 	//				SongMsgId song(data, item->fullId());
 | ||||
| 	//				audioPlayer()->play(song);
 | ||||
| 	//				if (App::main()) App::main()->documentPlayProgress(song);
 | ||||
| 	//			}
 | ||||
| 	//		} else if (data->voice() || data->isVideo()) {
 | ||||
| 	//			psOpenFile(location.name());
 | ||||
| 	//			if (App::main()) App::main()->mediaMarkRead(data);
 | ||||
| 	//		} else if (data->size < MediaViewImageSizeLimit) {
 | ||||
| 	//			if (!data->data().isEmpty() && playAnimation) {
 | ||||
| 	//				if (action == ActionOnLoadPlayInline && item->getMedia()) {
 | ||||
| 	//					item->getMedia()->playInline(item);
 | ||||
| 	//				} else {
 | ||||
| 	//					App::wnd()->showDocument(data, item);
 | ||||
| 	//				}
 | ||||
| 	//			} else if (location.accessEnable()) {
 | ||||
| 	//				if (item && (data->isAnimation() || QImageReader(location.name()).canRead())) {
 | ||||
| 	//					if (action == ActionOnLoadPlayInline && item->getMedia()) {
 | ||||
| 	//						item->getMedia()->playInline(item);
 | ||||
| 	//					} else {
 | ||||
| 	//						App::wnd()->showDocument(data, item);
 | ||||
| 	//					}
 | ||||
| 	//				} else {
 | ||||
| 	//					psOpenFile(location.name());
 | ||||
| 	//				}
 | ||||
| 	//				location.accessDisable();
 | ||||
| 	//			} else {
 | ||||
| 	//				psOpenFile(location.name());
 | ||||
| 	//			}
 | ||||
| 	//		} else {
 | ||||
| 	//			psOpenFile(location.name());
 | ||||
| 	//		}
 | ||||
| 	//		return;
 | ||||
| 	//	}
 | ||||
| 	//}
 | ||||
| 
 | ||||
| 	//QString filename = documentSaveFilename(data);
 | ||||
| 	//if (filename.isEmpty()) return;
 | ||||
| 	//if (!data->saveToCache()) {
 | ||||
| 	//	filename = documentSaveFilename(data);
 | ||||
| 	//	if (filename.isEmpty()) return;
 | ||||
| 	//}
 | ||||
| 
 | ||||
| 	//saveFile()
 | ||||
| 	//data->save(filename, action, item ? item->fullId() : FullMsgId());
 | ||||
| } | ||||
| 
 | ||||
| void Result::cancelFile() { | ||||
| 	if (!loading()) return; | ||||
| 
 | ||||
|  | @ -254,7 +399,7 @@ bool Result::loaded() const { | |||
| 
 | ||||
| 			_loader->deleteLater(); | ||||
| 			_loader->stop(); | ||||
| 			_loader = 0; | ||||
| 			_loader = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| 	return !_data.isEmpty(); | ||||
|  | @ -265,8 +410,14 @@ bool Result::displayLoading() const { | |||
| } | ||||
| 
 | ||||
| void Result::forget() { | ||||
| 	thumb->forget(); | ||||
| 	_thumb->forget(); | ||||
| 	_data.clear(); | ||||
| 	if (_document) { | ||||
| 		_document->forget(); | ||||
| 	} | ||||
| 	if (_photo) { | ||||
| 		_photo->forget(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| float64 Result::progress() const { | ||||
|  | @ -274,10 +425,10 @@ float64 Result::progress() const { | |||
| } | ||||
| 
 | ||||
| bool Result::hasThumbDisplay() const { | ||||
| 	if (!thumb->isNull()) { | ||||
| 	if (!_thumb->isNull()) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	if (type == Type::Contact) { | ||||
| 	if (_type == Type::Contact) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	if (sendData->hasLocationCoords()) { | ||||
|  |  | |||
|  | @ -42,18 +42,6 @@ private: | |||
| 	struct Creator; | ||||
| 
 | ||||
| public: | ||||
| 	enum class Type { | ||||
| 		Unknown, | ||||
| 		Photo, | ||||
| 		Video, | ||||
| 		Audio, | ||||
| 		Sticker, | ||||
| 		File, | ||||
| 		Gif, | ||||
| 		Article, | ||||
| 		Contact, | ||||
| 		Venue, | ||||
| 	}; | ||||
| 
 | ||||
| 	// Constructor is public only for MakeUnique<>() to work.
 | ||||
| 	// You should use create() static method instead.
 | ||||
|  | @ -62,22 +50,21 @@ public: | |||
| 	Result(const Result &other) = delete; | ||||
| 	Result &operator=(const Result &other) = delete; | ||||
| 
 | ||||
| 	uint64 queryId; | ||||
| 	QString id; | ||||
| 	Type type; | ||||
| 	DocumentData *document = nullptr; | ||||
| 	PhotoData *photo = nullptr; | ||||
| 	QString title, description, url, thumb_url; | ||||
| 	QString content_type, content_url; | ||||
| 	int width = 0; | ||||
| 	int height = 0; | ||||
| 	int duration = 0; | ||||
| 	uint64 getQueryId() const { | ||||
| 		return _queryId; | ||||
| 	} | ||||
| 	QString getId() const { | ||||
| 		return _id; | ||||
| 	} | ||||
| 
 | ||||
| 	ImagePtr thumb; | ||||
| 	// This is real SendClickHandler::onClick implementation for the specified
 | ||||
| 	// inline bot result. If it returns true you need to send this result.
 | ||||
| 	bool onChoose(Layout::ItemBase *layout); | ||||
| 
 | ||||
| 	void automaticLoadGif(); | ||||
| 	void automaticLoadSettingsChangedGif(); | ||||
| 	void saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading); | ||||
| 	void openFile(); | ||||
| 	void cancelFile(); | ||||
| 
 | ||||
| 	QByteArray data() const; | ||||
|  | @ -99,11 +86,43 @@ public: | |||
| 	~Result(); | ||||
| 
 | ||||
| private: | ||||
| 	enum class Type { | ||||
| 		Unknown, | ||||
| 		Photo, | ||||
| 		Video, | ||||
| 		Audio, | ||||
| 		Sticker, | ||||
| 		File, | ||||
| 		Gif, | ||||
| 		Article, | ||||
| 		Contact, | ||||
| 		Venue, | ||||
| 	}; | ||||
| 
 | ||||
| 	friend class internal::SendData; | ||||
| 	friend class Layout::ItemBase; | ||||
| 	struct Creator { | ||||
| 		uint64 queryId; | ||||
| 		Type type; | ||||
| 	}; | ||||
| 
 | ||||
| 	uint64 _queryId = 0; | ||||
| 	QString _id; | ||||
| 	Type _type = Type::Unknown; | ||||
| 	QString _title, _description, _url, _thumb_url; | ||||
| 	QString _content_type, _content_url; | ||||
| 	int _width = 0; | ||||
| 	int _height = 0; | ||||
| 	int _duration = 0; | ||||
| 
 | ||||
| 	mutable MTPDocument _mtpDocument = MTP_documentEmpty(MTP_long(0)); | ||||
| 	DocumentData *_document = nullptr; | ||||
| 
 | ||||
| 	mutable MTPPhoto _mtpPhoto = MTP_photoEmpty(MTP_long(0)); | ||||
| 	PhotoData *_photo = nullptr; | ||||
| 
 | ||||
| 	ImagePtr _thumb, _locationThumb; | ||||
| 
 | ||||
| 	UniquePointer<internal::SendData> sendData; | ||||
| 
 | ||||
| 	QByteArray _data; | ||||
|  |  | |||
|  | @ -28,11 +28,59 @@ namespace InlineBots { | |||
| namespace internal { | ||||
| 
 | ||||
| QString SendData::getLayoutTitle(const Result *owner) const { | ||||
| 	return owner->title; | ||||
| 	return owner->_title; | ||||
| } | ||||
| 
 | ||||
| QString SendData::getLayoutDescription(const Result *owner) const { | ||||
| 	return owner->description; | ||||
| 	return owner->_description; | ||||
| } | ||||
| 
 | ||||
| ImagePtr SendData::getResultThumb(const Result *owner) const { | ||||
| 	return owner->_thumb; | ||||
| } | ||||
| 
 | ||||
| int SendData::getResultWidth(const Result *owner) const { | ||||
| 	return owner->_width; | ||||
| } | ||||
| 
 | ||||
| int SendData::getResultHeight(const Result *owner) const { | ||||
| 	return owner->_height; | ||||
| } | ||||
| 
 | ||||
| QString SendData::getResultMime(const Result *owner) const { | ||||
| 	return owner->_content_type; | ||||
| } | ||||
| 
 | ||||
| QVector<MTPDocumentAttribute> SendData::prepareResultAttributes(const Result *owner) const { | ||||
| 	QVector<MTPDocumentAttribute> result; | ||||
| 	int duration = owner->_duration; | ||||
| 	QSize dimensions(owner->_width, owner->_height); | ||||
| 	using Type = Result::Type; | ||||
| 	if (owner->_type == Type::Gif) { | ||||
| 		const char *filename = (owner->_content_type == qstr("video/mp4") ? "animation.gif.mp4" : "animation.gif"); | ||||
| 		result.push_back(MTP_documentAttributeFilename(MTP_string(filename))); | ||||
| 		result.push_back(MTP_documentAttributeAnimated()); | ||||
| 		result.push_back(MTP_documentAttributeVideo(MTP_int(owner->_duration), MTP_int(owner->_width), MTP_int(owner->_height))); | ||||
| 	} else if (owner->_type == Type::Video) { | ||||
| 		result.push_back(MTP_documentAttributeVideo(MTP_int(owner->_duration), MTP_int(owner->_width), MTP_int(owner->_height))); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void SendData::setResultDocument(const Result *owner, const MTPDocument &document) const { | ||||
| 	owner->_mtpDocument = document; | ||||
| } | ||||
| 
 | ||||
| void SendData::setResultPhoto(const Result *owner, const MTPPhoto &photo) const { | ||||
| 	owner->_mtpPhoto = photo; | ||||
| } | ||||
| 
 | ||||
| MTPDocument SendData::getResultDocument(const Result *owner) const { | ||||
| 	return owner->_mtpDocument; | ||||
| } | ||||
| 
 | ||||
| MTPPhoto SendData::getResultPhoto(const Result *owner) const { | ||||
| 	return owner->_mtpPhoto; | ||||
| } | ||||
| 
 | ||||
| SendData::SentMTPMessageFields SendText::getSentMessageFields(const Result*) const { | ||||
|  | @ -61,13 +109,14 @@ SendData::SentMTPMessageFields SendContact::getSentMessageFields(const Result*) | |||
| } | ||||
| 
 | ||||
| QString SendContact::getLayoutDescription(const Result *owner) const { | ||||
| 	return App::formatPhone(_phoneNumber) + '\n' + owner->description; | ||||
| 	return App::formatPhone(_phoneNumber) + '\n' + SendData::getLayoutDescription(owner); | ||||
| } | ||||
| 
 | ||||
| SendData::SentMTPMessageFields SendPhoto::getSentMessageFields(const Result *owner) const { | ||||
| 	SentMTPMessageFields result; | ||||
| 
 | ||||
| 	QImage fileThumb(owner->thumb->pix().toImage()); | ||||
| 	ImagePtr resultThumb = getResultThumb(owner); | ||||
| 	QImage fileThumb(resultThumb->pix().toImage()); | ||||
| 
 | ||||
| 	QVector<MTPPhotoSize> photoSizes; | ||||
| 
 | ||||
|  | @ -75,13 +124,13 @@ SendData::SentMTPMessageFields SendPhoto::getSentMessageFields(const Result *own | |||
| 	ImagePtr thumbPtr = ImagePtr(thumb, "JPG"); | ||||
| 	photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); | ||||
| 
 | ||||
| 	QSize medium = resizeKeepAspect(owner->width, owner->height, 320, 320); | ||||
| 	QSize medium = resizeKeepAspect(getResultWidth(owner), getResultHeight(owner), 320, 320); | ||||
| 	photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); | ||||
| 
 | ||||
| 	photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(owner->width), MTP_int(owner->height), MTP_int(0))); | ||||
| 	photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(getResultWidth(owner)), MTP_int(getResultHeight(owner)), MTP_int(0))); | ||||
| 
 | ||||
| 	uint64 photoId = rand_value<uint64>(); | ||||
| 	PhotoData *ph = App::photoSet(photoId, 0, 0, unixtime(), thumbPtr, ImagePtr(medium.width(), medium.height()), ImagePtr(owner->width, owner->height)); | ||||
| 	PhotoData *ph = App::photoSet(photoId, 0, 0, unixtime(), thumbPtr, ImagePtr(medium.width(), medium.height()), ImagePtr(getResultWidth(owner), getResultHeight(owner))); | ||||
| 	MTPPhoto photo = MTP_photo(MTP_long(photoId), MTP_long(0), MTP_int(ph->date), MTP_vector<MTPPhotoSize>(photoSizes)); | ||||
| 
 | ||||
| 	result.media = MTP_messageMediaPhoto(photo, MTP_string(_caption)); | ||||
|  | @ -89,13 +138,14 @@ SendData::SentMTPMessageFields SendPhoto::getSentMessageFields(const Result *own | |||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| SendData::SentMTPMessageFields SendFile::getSentMessageFields(const Result *owner) const { | ||||
| 	SentMTPMessageFields result; | ||||
| void SendFile::prepareDocument(const Result *owner) const { | ||||
| 	if (getResultDocument(owner).type() != mtpc_documentEmpty) return; | ||||
| 
 | ||||
| 	ImagePtr resultThumb = getResultThumb(owner); | ||||
| 	MTPPhotoSize thumbSize; | ||||
| 	QPixmap thumb; | ||||
| 	int32 tw = owner->thumb->width(), th = owner->thumb->height(); | ||||
| 	if (tw > 0 && th > 0 && tw < 20 * th && th < 20 * tw && owner->thumb->loaded()) { | ||||
| 	int32 tw = resultThumb->width(), th = resultThumb->height(); | ||||
| 	if (tw > 0 && th > 0 && tw < 20 * th && th < 20 * tw && resultThumb->loaded()) { | ||||
| 		if (tw > th) { | ||||
| 			if (tw > 90) { | ||||
| 				th = th * 90 / tw; | ||||
|  | @ -106,41 +156,34 @@ SendData::SentMTPMessageFields SendFile::getSentMessageFields(const Result *owne | |||
| 			th = 90; | ||||
| 		} | ||||
| 		thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(tw), MTP_int(th), MTP_int(0)); | ||||
| 		thumb = owner->thumb->pixNoCache(tw, th, ImagePixSmooth); | ||||
| 		thumb = resultThumb->pixNoCache(tw, th, ImagePixSmooth); | ||||
| 	} else { | ||||
| 		tw = th = 0; | ||||
| 		thumbSize = MTP_photoSizeEmpty(MTP_string("")); | ||||
| 	} | ||||
| 	uint64 docId = rand_value<uint64>(); | ||||
| 	QVector<MTPDocumentAttribute> attributes; | ||||
| 
 | ||||
| 	int duration = getSentDuration(owner); | ||||
| 	QSize dimensions = getSentDimensions(owner); | ||||
| 	using Type = Result::Type; | ||||
| 	if (owner->type == Type::Gif) { | ||||
| 		attributes.push_back(MTP_documentAttributeFilename(MTP_string((owner->content_type == qstr("video/mp4") ? "animation.gif.mp4" : "animation.gif")))); | ||||
| 		attributes.push_back(MTP_documentAttributeAnimated()); | ||||
| 		attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(dimensions.width()), MTP_int(dimensions.height()))); | ||||
| 	} else if (owner->type == Type::Video) { | ||||
| 		attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(dimensions.width()), MTP_int(dimensions.height()))); | ||||
| 	} | ||||
| 	MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(owner->content_type), MTP_int(owner->data().size()), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes)); | ||||
| 	QVector<MTPDocumentAttribute> attributes = prepareResultAttributes(owner); | ||||
| 	MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(getResultMime(owner)), MTP_int(owner->data().size()), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes)); | ||||
| 	if (tw > 0 && th > 0) { | ||||
| 		App::feedDocument(document, thumb); | ||||
| 	} | ||||
| 	if (!owner->data().isEmpty()) { | ||||
| 		Local::writeStickerImage(mediaKey(DocumentFileLocation, MTP::maindc(), docId), owner->data()); | ||||
| 	} | ||||
| 	setResultDocument(owner, document); | ||||
| } | ||||
| 
 | ||||
| SendData::SentMTPMessageFields SendFile::getSentMessageFields(const Result *owner) const { | ||||
| 	SentMTPMessageFields result; | ||||
| 
 | ||||
| 	prepareDocument(owner); | ||||
| 
 | ||||
| 	MTPDocument document = getResultDocument(owner); | ||||
| 	result.media = MTP_messageMediaDocument(document, MTP_string(_caption)); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| int SendFile::getSentDuration(const Result *owner) const { | ||||
| 	return (_document && _document->duration()) ? _document->duration() : owner->duration; | ||||
| } | ||||
| QSize SendFile::getSentDimensions(const Result *owner) const { | ||||
| 	return (!_document || _document->dimensions.isEmpty()) ? QSize(owner->width, owner->height) : _document->dimensions; | ||||
| } | ||||
| 
 | ||||
| } // namespace internal
 | ||||
| } // namespace InlineBots
 | ||||
|  |  | |||
|  | @ -67,6 +67,20 @@ public: | |||
| 	virtual QString getLayoutTitle(const Result *owner) const; | ||||
| 	virtual QString getLayoutDescription(const Result *owner) const; | ||||
| 
 | ||||
| protected: | ||||
| 
 | ||||
| 	ImagePtr getResultThumb(const Result *owner) const; | ||||
| 	int getResultWidth(const Result *owner) const; | ||||
| 	int getResultHeight(const Result *owner) const; | ||||
| 	QString getResultMime(const Result *owner) const; | ||||
| 	QVector<MTPDocumentAttribute> prepareResultAttributes(const Result *owner) const; | ||||
| 
 | ||||
| 	void setResultDocument(const Result *owner, const MTPDocument &document) const; | ||||
| 	void setResultPhoto(const Result *owner, const MTPPhoto &photo) const; | ||||
| 
 | ||||
| 	MTPDocument getResultDocument(const Result *owner) const; | ||||
| 	MTPPhoto getResultPhoto(const Result *owner) const; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| // Plain text message.
 | ||||
|  | @ -221,12 +235,11 @@ public: | |||
| 	SentMTPMessageFields getSentMessageFields(const Result *owner) const override; | ||||
| 
 | ||||
| private: | ||||
| 	void prepareDocument(const Result *owner) const; | ||||
| 
 | ||||
| 	DocumentData *_document; | ||||
| 	QString _url, _caption; | ||||
| 
 | ||||
| 	int getSentDuration(const Result *owner) const; | ||||
| 	QSize getSentDimensions(const Result *owner) const; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace internal
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue