mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
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
11 changed files with 536 additions and 280 deletions
|
@ -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…
Add table
Reference in a new issue