diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 83cbfba299..18ce12d35a 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -113,6 +113,9 @@ namespace { typedef QHash LastPhotosMap; LastPhotosMap lastPhotosMap; + typedef QMap InlineResultLoaders; + InlineResultLoaders inlineResultLoaders; + style::color _msgServiceBg; style::color _msgServiceSelectBg; style::color _historyScrollBarColor; @@ -1459,12 +1462,12 @@ namespace App { delete convert->uploadingData; convert->uploadingData = 0; } - convert->access = access; - if (!convert->date && date) { + if (date) { + convert->access = access; convert->date = date; - convert->thumb = thumb; - convert->medium = medium; - convert->full = full; + if (convert->thumb->isNull() && !thumb->isNull()) convert->thumb = thumb; + if (convert->medium->isNull() && !medium->isNull()) convert->medium = medium; + if (convert->full->isNull() && !full->isNull()) convert->full = full; } } PhotosData::const_iterator i = ::photosData.constFind(photo); @@ -1479,12 +1482,12 @@ namespace App { ::photosData.insert(photo, result); } else { result = i.value(); - if (result != convert && !result->date && date) { + if (result != convert && date) { result->access = access; result->date = date; - result->thumb = thumb; - result->medium = medium; - result->full = full; + if (result->thumb->isNull() && !thumb->isNull()) result->thumb = thumb; + if (result->medium->isNull() && !medium->isNull()) result->medium = medium; + if (result->full->isNull() && !full->isNull()) result->full = full; } inLastIter = lastPhotosMap.find(result); } @@ -1520,13 +1523,15 @@ namespace App { convert->id = video; convert->status = FileReady; } - convert->access = access; - if (!convert->date && date) { + if (date) { + convert->access = access; convert->date = date; + if (convert->thumb->isNull() && !thumb->isNull()) { + convert->thumb = thumb; + } convert->duration = duration; convert->w = w; convert->h = h; - convert->thumb = thumb; convert->dc = dc; convert->size = size; } @@ -1542,13 +1547,15 @@ namespace App { ::videosData.insert(video, result); } else { result = i.value(); - if (result != convert && !result->date && date) { + if (result != convert && date) { result->access = access; result->date = date; result->duration = duration; result->w = w; result->h = h; - result->thumb = thumb; + if (result->thumb->isNull() && !thumb->isNull()) { + result->thumb = thumb; + } result->dc = dc; result->size = size; } @@ -1574,8 +1581,8 @@ namespace App { convert->id = audio; convert->status = FileReady; } - convert->access = access; - if (!convert->date && date) { + if (date) { + convert->access = access; convert->date = date; convert->mime = mime; convert->duration = duration; @@ -1594,7 +1601,7 @@ namespace App { ::audiosData.insert(audio, result); } else { result = i.value(); - if (result != convert && !result->date && date) { + if (result != convert && date) { result->access = access; result->date = date; result->mime = mime; @@ -1622,6 +1629,7 @@ namespace App { if (i != ::documentsData.cend() && i.value() == convert) { ::documentsData.erase(i); } + Local::copyStickerImage(mediaKey(DocumentFileLocation, convert->dc, convert->id), mediaKey(DocumentFileLocation, dc, document)); convert->id = document; convert->status = FileReady; if (cSavedGifs().indexOf(convert) >= 0) { // id changed @@ -1629,35 +1637,21 @@ namespace App { } sentSticker = !!convert->sticker(); } - convert->access = access; - if (!convert->date && date) { + if (date) { + convert->access = access; convert->date = date; convert->setattributes(attributes); convert->mime = mime; - convert->thumb = thumb; - convert->dc = dc; - convert->size = size; - convert->recountIsImage(); - } else { if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height())) { convert->thumb = thumb; } - if (convert->sticker() && !attributes.isEmpty() && (convert->sticker()->alt.isEmpty() || convert->sticker()->set.type() == mtpc_inputStickerSetEmpty)) { - for (QVector::const_iterator i = attributes.cbegin(), e = attributes.cend(); i != e; ++i) { - if (i->type() == mtpc_documentAttributeSticker) { - const MTPDdocumentAttributeSticker &d(i->c_documentAttributeSticker()); - if (d.valt.c_string().v.length() > 0) { - convert->sticker()->alt = qs(d.valt); - convert->sticker()->set = d.vstickerset; - } - } - } + convert->dc = dc; + convert->size = size; + convert->recountIsImage(); + if (convert->sticker() && convert->sticker()->loc.isNull() && !thumbLocation.isNull()) { + convert->sticker()->loc = thumbLocation; } } - if (convert->sticker() && convert->sticker()->loc.isNull() && !thumbLocation.isNull()) { - convert->sticker()->loc = thumbLocation; - } - const FileLocation &loc(convert->location(true)); if (!loc.isEmpty()) { Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), loc); @@ -1676,34 +1670,19 @@ namespace App { ::documentsData.insert(document, result); } else { result = i.value(); - if (result != convert) { - if (!result->date && date) { - result->access = access; - result->date = date; - result->setattributes(attributes); - result->mime = mime; + if (result != convert && date) { + result->access = access; + result->date = date; + result->setattributes(attributes); + result->mime = mime; + if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) { result->thumb = thumb; - result->dc = dc; - result->size = size; - result->recountIsImage(); - } else { - if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) { - result->thumb = thumb; - } - if (result->sticker() && !attributes.isEmpty() && (result->sticker()->alt.isEmpty() || result->sticker()->set.type() == mtpc_inputStickerSetEmpty)) { - for (QVector::const_iterator i = attributes.cbegin(), e = attributes.cend(); i != e; ++i) { - if (i->type() == mtpc_documentAttributeSticker) { - const MTPDdocumentAttributeSticker &d(i->c_documentAttributeSticker()); - if (d.valt.c_string().v.length() > 0) { - result->sticker()->alt = qs(d.valt); - result->sticker()->set = d.vstickerset; - } - } - } - } - if (result->sticker() && result->sticker()->loc.isNull() && !thumbLocation.isNull()) { - result->sticker()->loc = thumbLocation; - } + } + result->dc = dc; + result->size = size; + result->recountIsImage(); + if (result->sticker() && result->sticker()->loc.isNull() && !thumbLocation.isNull()) { + result->sticker()->loc = thumbLocation; } } } @@ -2522,6 +2501,19 @@ namespace App { if (changeInMin) App::main()->updateMutedIn(changeInMin); } + void regInlineResultLoader(FileLoader *loader, InlineResult *result) { + ::inlineResultLoaders.insert(loader, result); + } + + void unregInlineResultLoader(FileLoader *loader) { + ::inlineResultLoaders.remove(loader); + } + + InlineResult *inlineResultFromLoader(FileLoader *loader) { + InlineResultLoaders::const_iterator i = ::inlineResultLoaders.find(loader); + return (i == ::inlineResultLoaders.cend()) ? 0 : i.value(); + } + inline void insertReplyMarkup(ChannelId channelId, MsgId msgId, const ReplyMarkup &markup) { if (channelId == NoChannel) { replyMarkups.insert(msgId, markup); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 0a46a235fc..c01fdf9802 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -246,6 +246,10 @@ namespace App { void unregMuted(PeerData *peer); void updateMuted(); + void regInlineResultLoader(FileLoader *loader, InlineResult *result); + void unregInlineResultLoader(FileLoader *loader); + InlineResult *inlineResultFromLoader(FileLoader *loader); + void feedReplyMarkup(ChannelId channelId, MsgId msgId, const MTPReplyMarkup &markup); void clearReplyMarkup(ChannelId channelId, MsgId msgId); const ReplyMarkup &replyMarkup(ChannelId channelId, MsgId msgId); diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index cf419735be..2e738e16a8 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -1432,15 +1432,61 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { if (row < _inlineRows.size() && col < _inlineRows.at(row).items.size()) { if (down) { if (down->type() == qstr("SendInlineItemLink") && e->button() == Qt::LeftButton) { - DocumentData *doc = _inlineRows.at(row).items.at(col)->document(); - if (!doc) return; - - if (doc->loaded()) { - emit selected(doc); - } else if (doc->loading()) { - doc->cancel(); - } else { - DocumentOpenLink::doOpen(doc, ActionOnLoadNone); + LayoutInlineItem *item = _inlineRows.at(row).items.at(col); + PhotoData *photo = item->photo(); + DocumentData *doc = item->document(); + InlineResult *result = item->result(); + if (doc) { + if (doc->loaded()) { + emit selected(doc); + } else if (doc->loading()) { + doc->cancel(); + } else { + DocumentOpenLink::doOpen(doc, ActionOnLoadNone); + } + } else if (photo) { + if (photo->medium->loaded() || photo->thumb->loaded()) { + emit selected(photo); + } else if (!photo->medium->loading()) { + photo->thumb->loadEvenCancelled(); + photo->medium->loadEvenCancelled(); + } + } else if (result) { + if (result->type == qstr("gif")) { + if (result->doc) { + if (result->doc->loaded()) { + emit selected(result, _inlineBot); + } else if (result->doc->loading()) { + result->doc->cancel(); + } else { + DocumentOpenLink::doOpen(result->doc, ActionOnLoadNone); + } + } else if (result->loaded()) { + emit selected(result, _inlineBot); + } else if (result->loading()) { + result->cancelFile(); + Ui::repaintInlineItem(item); + } else { + result->saveFile(QString(), LoadFromCloudOrLocal, false); + Ui::repaintInlineItem(item); + } + } else if (result->type == qstr("photo")) { + if (result->photo) { + if (result->photo->medium->loaded() || result->photo->thumb->loaded()) { + emit selected(result, _inlineBot); + } else if (!result->photo->medium->loading()) { + result->photo->thumb->loadEvenCancelled(); + result->photo->medium->loadEvenCancelled(); + } + } else if (result->thumb->loaded()) { + emit selected(result, _inlineBot); + } else if (!result->thumb->loading()) { + result->thumb->loadEvenCancelled(); + Ui::repaintInlineItem(item); + } + } else { + emit selected(result, _inlineBot); + } } } else { down->onClick(e->button()); @@ -1558,7 +1604,7 @@ void StickerPanInner::clearSelection(bool fast) { } void StickerPanInner::hideFinish() { - clearInlineRows(); + clearInlineRows(false); for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) { i.value()->document()->forget(); } @@ -1607,13 +1653,15 @@ void StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *re } if (!layout) return; - inlineRowFinalize(row, sumWidth, layout->fullLine()); + if (inlineRowFinalize(row, sumWidth, layout->fullLine())) { + layout->setPosition(_inlineRows.size() * MatrixRowShift); + } row.items.push_back(layout); sumWidth += layout->maxWidth(); } -void StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) { - if (row.items.isEmpty()) return; +bool StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) { + if (row.items.isEmpty()) return false; bool full = (row.items.size() >= SavedGifsMaxPerRow); bool big = (sumWidth >= st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - (row.items.size() - 1) * st::inlineResultsSkip); @@ -1622,12 +1670,14 @@ void StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool fo row = InlineRow(); row.items.reserve(SavedGifsMaxPerRow); sumWidth = 0; + return true; } + return false; } void StickerPanInner::refreshSavedGifs() { if (_showingSavedGifs) { - clearInlineRows(); + clearInlineRows(false); if (_showingInlineItems) { const SavedGifs &saved(cSavedGifs()); if (saved.isEmpty()) { @@ -1657,15 +1707,23 @@ void StickerPanInner::refreshSavedGifs() { } void StickerPanInner::inlineBotChanged() { - refreshInlineRows(0, InlineResults()); + refreshInlineRows(0, InlineResults(), true); deleteUnusedInlineLayouts(); } -void StickerPanInner::clearInlineRows() { - clearSelection(true); - for (InlineRows::const_iterator i = _inlineRows.cbegin(), e = _inlineRows.cend(); i != e; ++i) { - for (InlineItems::const_iterator j = i->items.cbegin(), end = i->items.cend(); j != end; ++j) { - (*j)->setPosition(-1); +void StickerPanInner::clearInlineRows(bool resultsDeleted) { + if (resultsDeleted) { + if (_showingInlineItems) { + _selected = _pressedSel = -1; + } + } else { + if (_showingInlineItems) { + clearSelection(true); + } + for (InlineRows::const_iterator i = _inlineRows.cbegin(), e = _inlineRows.cend(); i != e; ++i) { + for (InlineItems::const_iterator j = i->items.cbegin(), end = i->items.cend(); j != end; ++j) { + (*j)->setPosition(-1); + } } } _inlineRows.clear(); @@ -1690,9 +1748,11 @@ LayoutInlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *resul if (result->type == qstr("gif")) { layout = new LayoutInlineGif(result, 0, false); } else if (result->type == qstr("photo")) { + layout = new LayoutInlinePhoto(result, 0); } else if (result->type == qstr("web_player_video")) { + // layout = new LayoutInlineWebVideo(result, 0); } else if (result->type == qstr("article")) { - return 0; +// layout = new LayoutInlineArticle(result, 0); } if (!layout) return 0; @@ -1706,7 +1766,7 @@ LayoutInlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *resul } void StickerPanInner::deleteUnusedGifLayouts() { - if (_inlineRows.isEmpty()) { // delete all + if (_inlineRows.isEmpty() || !_showingSavedGifs) { // delete all for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) { delete i.value(); } @@ -1724,7 +1784,7 @@ void StickerPanInner::deleteUnusedGifLayouts() { } void StickerPanInner::deleteUnusedInlineLayouts() { - if (_inlineRows.isEmpty()) { // delete all + if (_inlineRows.isEmpty() || _showingSavedGifs) { // delete all for (InlineLayouts::const_iterator i = _inlineLayouts.cbegin(), e = _inlineLayouts.cend(); i != e; ++i) { delete i.value(); } @@ -1802,10 +1862,10 @@ uint64 StickerPanInner::currentSet(int yOffset) const { return _sets.isEmpty() ? RecentStickerSetId : _sets.back().id; } -void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results) { +void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted) { int32 count = results.size(), until = 0, untilrow = 0, untilcol = 0; if (!count) { - _inlineRows.clear(); + clearInlineRows(resultsDeleted); _showingSavedGifs = true; if (_showingInlineItems) { refreshSavedGifs(); @@ -1816,6 +1876,7 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu } t_assert(bot != 0); + _inlineBot = bot; _inlineBotTitle = lng_inline_bot_results(lt_inline_bot, bot->username.isEmpty() ? bot->name : ('@' + bot->username)); _showingInlineItems = true; @@ -2483,6 +2544,8 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent) connect(&e_inner, SIGNAL(selected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr))); connect(&s_inner, SIGNAL(selected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*))); + connect(&s_inner, SIGNAL(selected(PhotoData*)), this, SIGNAL(photoSelected(PhotoData*))); + connect(&s_inner, SIGNAL(selected(InlineResult*,UserData*)), this, SIGNAL(inlineResultSelected(InlineResult*,UserData*))); connect(&s_switch, SIGNAL(clicked()), this, SLOT(onSwitch())); connect(&e_switch, SIGNAL(clicked()), this, SLOT(onSwitch())); @@ -3404,12 +3467,18 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) { const MTPDbotInlineResult &r(v.at(i).c_botInlineResult()); result->id = qs(r.vid); result->type = qs(r.vtype); - result->title = qs(r.vtitle); - result->description = qs(r.vdescription); - result->url = qs(r.vurl); - result->thumb_url = qs(r.vthumb_url); - result->content_type = qs(r.vcontent_type); - result->content_url = qs(r.vcontent_url); + result->title = r.has_title() ? qs(r.vtitle) : QString(); + result->description = r.has_description() ? qs(r.vdescription) : QString(); + result->url = r.has_url() ? qs(r.vurl) : QString(); + result->thumb_url = r.has_thumb_url() ? qs(r.vthumb_url) : QString(); + result->content_type = r.has_content_type() ? qs(r.vcontent_type) : QString(); + result->content_url = r.has_content_url() ? qs(r.vcontent_url) : QString(); + result->width = r.has_w() ? r.vw.v : 0; + result->height = r.has_h() ? r.vh.v : 0; + result->duration = r.has_duration() ? r.vduration.v : 0; + 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; } @@ -3460,22 +3529,19 @@ bool EmojiPan::inlineResultsFail(const RPCError &error) { void EmojiPan::queryInlineBot(UserData *bot, QString query) { bool force = false; if (bot != _inlineBot) { - LOG(("Inline bot changed! to @%1").arg(bot->username)); inlineBotChanged(); _inlineBot = bot; force = true; } - if (_inlineRequestId) { - MTP::cancel(_inlineRequestId); - _inlineRequestId = 0; - } if (_inlineQuery != query || force) { + if (_inlineRequestId) { + MTP::cancel(_inlineRequestId); + _inlineRequestId = 0; + } if (_inlineCache.contains(query)) { - LOG(("Query %1 found in cache!").arg(query)); _inlineQuery = query; showInlineRows(true); } else { - LOG(("Scheduling request for %1!").arg(query)); _inlineNextQuery = query; _inlineRequestTimer.start(InlineBotRequestDelay); } @@ -3492,7 +3558,6 @@ void EmojiPan::onInlineRequest() { nextOffset = i.value()->nextOffset; if (nextOffset.isEmpty()) return; } - LOG(("Requesting %1 with offset \"%2\"!").arg(_inlineQuery).arg(nextOffset)); _inlineRequestId = MTP::send(MTPmessages_GetInlineBotResults(_inlineBot->inputUser, MTP_string(_inlineQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::inlineResultsDone), rpcFail(&EmojiPan::inlineResultsFail)); } @@ -3504,24 +3569,23 @@ void EmojiPan::showInlineRows(bool newResults) { _inlineNextOffset = i.value()->nextOffset; } - if (clear) LOG(("Clearing results!")); else LOG(("Showing results: %1").arg(i.value()->results.size())); - s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results); + s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results, false); if (newResults) s_scroll.scrollToY(0); if (clear && !isHidden() && _stickersShown && s_inner.inlineResultsShown()) { hideStart(); } else if (!clear) { _hideTimer.stop(); - if (!_stickersShown) { - if (!isHidden() || _hiding) { + if (!isHidden() || _hiding) { + if (!_stickersShown) { onSwitch(); - } else { - _stickersShown = true; - if (isHidden()) { - show(); - a_opacity = anim::fvalue(0, 1); - a_opacity.update(0, anim::linear); - _cache = _fromCache = _toCache = QPixmap(); - } + } + } else { + _stickersShown = true; + if (isHidden()) { + show(); + a_opacity = anim::fvalue(0, 1); + a_opacity.update(0, anim::linear); + _cache = _fromCache = _toCache = QPixmap(); } } if (isHidden() || _hiding) { diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h index e6f55f906e..22fb4cdc98 100644 --- a/Telegram/SourceFiles/dropdown.h +++ b/Telegram/SourceFiles/dropdown.h @@ -341,7 +341,7 @@ public: void refreshStickers(); void refreshRecentStickers(bool resize = true); void refreshSavedGifs(); - void refreshInlineRows(UserData *bot, const InlineResults &results); + void refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted); void refreshRecent(); void inlineBotChanged(); @@ -363,7 +363,7 @@ public: } ~StickerPanInner() { - clearInlineRows(); + clearInlineRows(true); deleteUnusedGifLayouts(); deleteUnusedInlineLayouts(); } @@ -378,6 +378,9 @@ public slots: signals: void selected(DocumentData *sticker); + void selected(PhotoData *photo); + void selected(InlineResult *result, UserData *bot); + void removing(quint64 setId); void refreshIcons(); @@ -423,6 +426,7 @@ private: QList _custom; bool _showingSavedGifs, _showingInlineItems; + UserData *_inlineBot; QString _inlineBotTitle; uint64 _lastScrolled; QTimer _updateInlineItems; @@ -436,7 +440,7 @@ private: }; typedef QVector InlineRows; InlineRows _inlineRows; - void clearInlineRows(); + void clearInlineRows(bool resultsDeleted); typedef QMap GifLayouts; GifLayouts _gifLayouts; @@ -447,7 +451,7 @@ private: LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position); void inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth); - void inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false); + bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false); InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0); void deleteUnusedGifLayouts(); @@ -600,6 +604,9 @@ signals: void emojiSelected(EmojiPtr emoji); void stickerSelected(DocumentData *sticker); + void photoSelected(PhotoData *photo); + void inlineResultSelected(InlineResult *result, UserData *bot); + void updateStickers(); private: diff --git a/Telegram/SourceFiles/gui/flattextarea.cpp b/Telegram/SourceFiles/gui/flattextarea.cpp index d9785747bc..755241e2b8 100644 --- a/Telegram/SourceFiles/gui/flattextarea.cpp +++ b/Telegram/SourceFiles/gui/flattextarea.cpp @@ -294,6 +294,8 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&i start = text.mid(inlineUsernameStart + inlineUsernameLength + 1); return; } + } else { + inlineUsernameLength = 0; } } if (!inlineUsernameLength) { diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index a244fbbef5..4dc01b085a 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1561,13 +1561,25 @@ HistoryItem *History::createItemForwarded(HistoryBlock *block, MsgId id, QDateTi return regItem(new HistoryForwarded(this, block, id, date, from, msg)); } -HistoryItem *History::createItemDocument(HistoryBlock *block, MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { +HistoryItem *History::createItemDocument(HistoryBlock *block, MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { + HistoryItem *result = 0; + + if ((flags & MTPDmessage::flag_reply_to_msg_id) && replyTo > 0) { + result = new HistoryReply(this, block, id, flags, viaBotId, replyTo, date, from, doc, caption); + } else { + result = new HistoryMessage(this, block, id, flags, viaBotId, date, from, doc, caption); + } + + return regItem(result); +} + +HistoryItem *History::createItemPhoto(HistoryBlock *block, MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { HistoryItem *result = 0; if (flags & MTPDmessage::flag_reply_to_msg_id && replyTo > 0) { - result = new HistoryReply(this, block, id, flags, replyTo, date, from, doc, caption); + result = new HistoryReply(this, block, id, flags, viaBotId, replyTo, date, from, photo, caption); } else { - result = new HistoryMessage(this, block, id, flags, date, from, doc, caption); + result = new HistoryMessage(this, block, id, flags, viaBotId, date, from, photo, caption); } return regItem(result); @@ -1633,7 +1645,7 @@ HistoryItem *History::addNewForwarded(MsgId id, QDateTime date, int32 from, Hist return addNewItem(to, newBlock, createItemForwarded(to, id, date, from, item), true); } -HistoryItem *History::addNewDocument(MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { +HistoryItem *History::addNewDocument(MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { HistoryBlock *to = 0; bool newBlock = blocks.isEmpty(); if (newBlock) { @@ -1641,7 +1653,18 @@ HistoryItem *History::addNewDocument(MsgId id, int32 flags, MsgId replyTo, QDate } else { to = blocks.back(); } - return addNewItem(to, newBlock, createItemDocument(to, id, flags, replyTo, date, from, doc, caption), true); + return addNewItem(to, newBlock, createItemDocument(to, id, flags, viaBotId, replyTo, date, from, doc, caption), true); +} + +HistoryItem *History::addNewPhoto(MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { + HistoryBlock *to = 0; + bool newBlock = blocks.isEmpty(); + if (newBlock) { + to = new HistoryBlock(this); + } else { + to = blocks.back(); + } + return addNewItem(to, newBlock, createItemPhoto(to, id, flags, viaBotId, replyTo, date, from, photo, caption), true); } void History::createInitialDateBlock(const QDateTime &date) { @@ -3209,8 +3232,8 @@ HistoryFileMedia::~HistoryFileMedia() { deleteAndMark(_animation); } -HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, const QString &caption, HistoryItem *parent) : HistoryFileMedia() -, _data(App::feedPhoto(photo)) +HistoryPhoto::HistoryPhoto(PhotoData *photo, const QString &caption, const HistoryItem *parent) : HistoryFileMedia() +, _data(photo) , _pixw(1) , _pixh(1) , _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { @@ -3222,15 +3245,6 @@ HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, const QString &caption, Histo init(); } -HistoryPhoto::HistoryPhoto(PhotoData *photo) : HistoryFileMedia() -, _data(photo) -, _pixw(1) -, _pixh(1) { - setLinks(new PhotoLink(_data), new PhotoSaveLink(_data), new PhotoCancelLink(_data)); - - init(); -} - HistoryPhoto::HistoryPhoto(PeerData *chat, const MTPDphoto &photo, int32 width) : HistoryFileMedia() , _data(App::feedPhoto(photo)) , _pixw(1) @@ -5181,7 +5195,7 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) { _attach = new HistoryDocument(_data->doc, QString(), parent); } } else if (_data->photo) { - _attach = new HistoryPhoto(_data->photo); + _attach = new HistoryPhoto(_data->photo, QString(), parent); } } @@ -5798,23 +5812,23 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPD , _text(st::msgMinWidth) , _textWidth(0) , _textHeight(0) +, _viaBot(msg.has_via_bot_id() ? App::userLoaded(peerFromUser(msg.vvia_bot_id)) : 0) , _media(0) -, _views(msg.has_views() ? msg.vviews.v : -1) -{ +, _views(msg.has_views() ? msg.vviews.v : -1) { QString text(textClean(qs(msg.vmessage))); initTime(); initMedia(msg.has_media() ? (&msg.vmedia) : 0, text); setText(text, msg.has_entities() ? entitiesFromMTP(msg.ventities.c_vector().v) : EntitiesInText()); } -HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities, HistoryMedia *fromMedia) : +HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities, HistoryMedia *fromMedia) : HistoryItem(history, block, msgId, flags, date, from) , _text(st::msgMinWidth) , _textWidth(0) , _textHeight(0) +, _viaBot(viaBotId ? App::userLoaded(peerFromUser(viaBotId)) : 0) , _media(0) -, _views(fromChannel() ? 1 : -1) -{ +, _views(fromChannel() ? 1 : -1) { initTime(); if (fromMedia) { _media = fromMedia->clone(); @@ -5823,19 +5837,33 @@ HistoryItem(history, block, msgId, flags, date, from) setText(msg, entities); } -HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, DocumentData *doc, const QString &caption) : +HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) : HistoryItem(history, block, msgId, flags, date, from) , _text(st::msgMinWidth) , _textWidth(0) , _textHeight(0) +, _viaBot(viaBotId ? App::userLoaded(peerFromUser(viaBotId)) : 0) , _media(0) -, _views(fromChannel() ? 1 : -1) -{ +, _views(fromChannel() ? 1 : -1) { initTime(); initMediaFromDocument(doc, caption); setText(QString(), EntitiesInText()); } +HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) : +HistoryItem(history, block, msgId, flags, date, from) +, _text(st::msgMinWidth) +, _textWidth(0) +, _textHeight(0) +, _viaBot(viaBotId ? App::userLoaded(peerFromUser(viaBotId)) : 0) +, _media(0) +, _views(fromChannel() ? 1 : -1) { + initTime(); + _media = new HistoryPhoto(photo, caption, this); + _media->regItem(this); + setText(QString(), EntitiesInText()); +} + QString formatViewsCount(int32 views) { if (views > 999999) { views /= 100000; @@ -5886,7 +5914,7 @@ void HistoryMessage::initMedia(const MTPMessageMedia *media, QString ¤tTex case mtpc_messageMediaPhoto: { const MTPDmessageMediaPhoto &photo(media->c_messageMediaPhoto()); if (photo.vphoto.type() == mtpc_photo) { - _media = new HistoryPhoto(photo.vphoto.c_photo(), qs(photo.vcaption), this); + _media = new HistoryPhoto(App::feedPhoto(photo.vphoto.c_photo()), qs(photo.vcaption), this); } } break; case mtpc_messageMediaVideo: { @@ -6468,7 +6496,8 @@ HistoryMessage::~HistoryMessage() { } } -HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessage &msg) : HistoryMessage(history, block, msg) +HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessage &msg) +: HistoryMessage(history, block, msg) , fwdDate(::date(msg.vfwd_date)) , fwdFrom(App::peer(peerFromMTP(msg.vfwd_from_id))) , fwdFromVersion(fwdFrom->nameVersion) @@ -6476,7 +6505,8 @@ HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const fwdNameUpdated(); } -HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, QDateTime date, int32 from, HistoryMessage *msg) : HistoryMessage(history, block, id, newMessageFlags(history->peer) | (!history->peer->isChannel() && msg->getMedia() && (msg->getMedia()->type() == MediaTypeAudio/* || msg->getMedia()->type() == MediaTypeVideo*/) ? MTPDmessage::flag_media_unread : 0), date, from, msg->HistoryMessage::originalText(), msg->HistoryMessage::originalEntities(), msg->getMedia()) +HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, QDateTime date, int32 from, HistoryMessage *msg) +: HistoryMessage(history, block, id, newMessageFlags(history->peer) | (!history->peer->isChannel() && msg->getMedia() && (msg->getMedia()->type() == MediaTypeAudio/* || msg->getMedia()->type() == MediaTypeVideo*/) ? MTPDmessage::flag_media_unread : 0), msg->viaBot() ? peerToUser(msg->viaBot()->id) : 0, date, from, msg->HistoryMessage::originalText(), msg->HistoryMessage::originalEntities(), msg->getMedia()) , fwdDate(msg->dateForwarded()) , fwdFrom(msg->fromForwarded()) , fwdFromVersion(fwdFrom->nameVersion) @@ -6647,8 +6677,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, const MTPDmess } } -HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) -: HistoryMessage(history, block, msgId, flags, date, from, doc, caption) +HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) +: HistoryMessage(history, block, msgId, flags, viaBotId, date, from, doc, caption) , replyToMsgId(replyTo) , replyToMsg(0) , replyToVersion(0) @@ -6658,6 +6688,16 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i } } +HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) +: HistoryMessage(history, block, msgId, flags, viaBotId, date, from, photo, caption) +, replyToMsgId(replyTo) +, replyToMsg(0) +, replyToVersion(0) +, _maxReplyWidth(0) { + if (!updateReplyTo() && App::api()) { + App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId); + } +} QString HistoryReply::selectedText(uint32 selection) const { if (selection != FullSelection || !replyToMsg) return HistoryMessage::selectedText(selection); QString result, original = HistoryMessage::selectedText(selection); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index a322508e62..6d26294ac4 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -195,13 +195,15 @@ public: HistoryItem *createItem(HistoryBlock *block, const MTPMessage &msg, bool applyServiceAction); HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, QDateTime date, int32 from, HistoryMessage *msg); - HistoryItem *createItemDocument(HistoryBlock *block, MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryItem *createItemDocument(HistoryBlock *block, MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryItem *createItemPhoto(HistoryBlock *block, MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption); HistoryItem *addNewService(MsgId msgId, QDateTime date, const QString &text, int32 flags = 0, HistoryMedia *media = 0, bool newMsg = true); HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type); HistoryItem *addToHistory(const MTPMessage &msg); HistoryItem *addNewForwarded(MsgId id, QDateTime date, int32 from, HistoryMessage *item); - HistoryItem *addNewDocument(MsgId id, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryItem *addNewDocument(MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryItem *addNewPhoto(MsgId id, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption); void addOlderSlice(const QVector &slice, const QVector *collapsed); void addNewerSlice(const QVector &slice, const QVector *collapsed); @@ -1271,8 +1273,7 @@ private: class HistoryPhoto : public HistoryFileMedia { public: - HistoryPhoto(const MTPDphoto &photo, const QString &caption, HistoryItem *parent); - HistoryPhoto(PhotoData *photo); + HistoryPhoto(PhotoData *photo, const QString &caption, const HistoryItem *parent); HistoryPhoto(PeerData *chat, const MTPDphoto &photo, int32 width = 0); HistoryPhoto(const HistoryPhoto &other); void init(); @@ -1904,8 +1905,9 @@ class HistoryMessage : public HistoryItem { public: HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg); - HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities, HistoryMedia *media); // local forwarded - HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, DocumentData *doc, const QString &caption); // local sticker and reply sticker + HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities, HistoryMedia *media); // local forwarded + HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption); // local document + HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption); // local photo void initTime(); void initMedia(const MTPMessageMedia *media, QString ¤tText); @@ -1913,6 +1915,10 @@ public: void initDimensions(); void fromNameUpdated() const; + UserData *viaBot() const { + return _viaBot; + } + int32 plainMaxWidth() const; void countPositionAndSize(int32 &left, int32 &width) const; @@ -2030,6 +2036,7 @@ protected: Text _text; int32 _textWidth, _textHeight; + UserData *_viaBot; HistoryMedia *_media; QString _timeText; @@ -2091,7 +2098,8 @@ class HistoryReply : public HistoryMessage { public: HistoryReply(History *history, HistoryBlock *block, const MTPDmessage &msg); - HistoryReply(History *history, HistoryBlock *block, MsgId msgId, int32 flags, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryReply(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryReply(History *history, HistoryBlock *block, MsgId msgId, int32 flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption); void initDimensions(); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index d0ef95d42d..fb060ed341 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -2708,6 +2708,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr))); connect(&_emojiPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*))); + connect(&_emojiPan, SIGNAL(photoSelected(PhotoData*)), this, SLOT(onPhotoSend(PhotoData*))); + connect(&_emojiPan, SIGNAL(inlineResultSelected(InlineResult*,UserData*)), this, SLOT(onInlineResultSend(InlineResult*,UserData*))); connect(&_emojiPan, SIGNAL(updateStickers()), this, SLOT(updateStickers())); connect(&_sendActionStopTimer, SIGNAL(timeout()), this, SLOT(onCancelSendAction())); connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreviewTimeout())); @@ -6267,7 +6269,15 @@ void HistoryWidget::onFieldTabbed() { } void HistoryWidget::onStickerSend(DocumentData *sticker) { - if (!_history || !sticker || !canSendMessages(_peer)) return; + sendExistingDocument(sticker, QString(), 0); +} + +void HistoryWidget::onPhotoSend(PhotoData *photo) { + sendExistingPhoto(photo, QString(), 0); +} + +void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) { + if (!_history || !result || !canSendMessages(_peer)) return; App::main()->readServerHistory(_history, false); fastShowAtEnd(_history); @@ -6290,13 +6300,156 @@ void HistoryWidget::onStickerSend(DocumentData *sticker) { } else { flags |= MTPDmessage::flag_from_id; } - _history->addNewDocument(newId.msg, flags, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), sticker, QString()); + if (bot) { + flags |= MTPDmessage::flag_via_bot_id; + } - _history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), _peer->input, MTP_int(replyToId()), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(sticker->id), MTP_long(sticker->access)), MTP_string("")), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId); + if (result->message.isEmpty()) { + if (result->doc) { + _history->addNewDocument(newId.msg, flags, bot ? peerToUser(bot->id) : 0, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), result->doc, result->caption); + } else if (result->photo) { + _history->addNewPhoto(newId.msg, flags, bot ? peerToUser(bot->id) : 0, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), result->photo, result->caption); + } else if (result->type == qstr("gif")) { + MTPPhotoSize thumbSize; + QPixmap thumb; + int32 tw = result->thumb->width(), th = result->thumb->height(); + if (tw > 0 && th > 0 && tw < 20 * th && th < 20 * tw && result->thumb->loaded()) { + if (tw > th) { + if (tw > 90) { + th = th * 90 / tw; + tw = 90; + } + } else if (th > 90) { + tw = tw * 90 / th; + 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 = result->thumb->pixNoCache(tw, th, true, false, false); + } else { + tw = th = 0; + thumbSize = MTP_photoSizeEmpty(MTP_string("")); + } + uint64 docId = MTP::nonce(); + QVector attributes(1, MTP_documentAttributeFilename(MTP_string((result->content_type == qstr("video/mp4") ? "animation.gif.mp4" : "animation.gif")))); + attributes.push_back(MTP_documentAttributeAnimated()); + attributes.push_back(MTP_documentAttributeVideo(MTP_int(result->duration), MTP_int(result->width), MTP_int(result->height))); + MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(result->content_type), MTP_int(result->data().size()), thumbSize, MTP_int(MTP::maindc()), MTP_vector(attributes)); + if (tw > 0 && th > 0) { + App::feedDocument(document, thumb); + } + Local::writeStickerImage(mediaKey(DocumentFileLocation, MTP::maindc(), docId), result->data()); + _history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(_history->peer->id), MTPPeer(), MTPint(), MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(document, MTP_string(result->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); + } else if (result->type == qstr("photo")) { + QImage fileThumb(result->thumb->pix().toImage()); + + PreparedPhotoThumbs photoThumbs; + QVector photoSizes; + + QPixmap thumb = (fileThumb.width() > 100 || fileThumb.height() > 100) ? QPixmap::fromImage(fileThumb.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fileThumb); + photoThumbs.insert('s', thumb); + 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))); + + QPixmap medium = (fileThumb.width() > 320 || fileThumb.height() > 320) ? QPixmap::fromImage(fileThumb.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fileThumb); + photoThumbs.insert('m', medium); + 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))); + + MTPPhoto photo = MTP_photo(MTP_long(MTP::nonce()), MTP_long(0), MTP_int(unixtime()), MTP_vector(photoSizes)); + _history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(_history->peer->id), MTPPeer(), MTPint(), MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(photo, MTP_string(result->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); + } + } else { + if (result->noWebPage) { + sendFlags |= MTPmessages_SendMessage::flag_no_webpage; + } + _history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(_history->peer->id), MTPPeer(), MTPint(), MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(result->message), MTP_messageMediaEmpty(), MTPnullMarkup, linksToMTP(result->entities), MTP_int(1)), NewMessageUnread); + } + _history->sendRequestId = MTP::send(MTPmessages_SendInlineBotResult(MTP_int(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); App::main()->finishForwarding(_history, _broadcast.checked()); cancelReply(lastKeyboardUsed); - if (sticker->sticker()) App::main()->incrementSticker(sticker); + App::historyRegRandom(randomId, newId); + + setFieldText(QString()); + _saveDraftText = true; + _saveDraftStart = getms(); + onDraftSave(); + + if (!_attachMention.isHidden()) _attachMention.hideStart(); + if (!_attachType.isHidden()) _attachType.hideStart(); + if (!_emojiPan.isHidden()) _emojiPan.hideStart(); + + _field.setFocus(); +} + +void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption, UserData *bot) { + if (!_history || !doc || !canSendMessages(_peer)) return; + + App::main()->readServerHistory(_history, false); + fastShowAtEnd(_history); + + uint64 randomId = MTP::nonce(); + FullMsgId newId(_channel, clientMsgId()); + + bool lastKeyboardUsed = lastForceReplyReplied(); + + bool out = !_peer->isSelf(), unread = !_peer->isSelf(); + int32 flags = newMessageFlags(_peer) | MTPDmessage::flag_media; // unread, out + int32 sendFlags = 0; + if (replyToId()) { + flags |= MTPDmessage::flag_reply_to_msg_id; + sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; + } + bool fromChannelName = _peer->isChannel() && !_peer->isMegagroup() && _peer->asChannel()->canPublish() && (_peer->asChannel()->isBroadcast() || _broadcast.checked()); + if (fromChannelName) { + sendFlags |= MTPmessages_SendMedia::flag_broadcast; + } else { + flags |= MTPDmessage::flag_from_id; + } + _history->addNewDocument(newId.msg, flags, bot ? peerToUser(bot->id) : 0, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), doc, caption); + + _history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), _peer->input, MTP_int(replyToId()), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(doc->id), MTP_long(doc->access)), MTP_string(caption)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId); + App::main()->finishForwarding(_history, _broadcast.checked()); + cancelReply(lastKeyboardUsed); + + if (doc->sticker()) App::main()->incrementSticker(doc); + + App::historyRegRandom(randomId, newId); + + if (!_attachMention.isHidden()) _attachMention.hideStart(); + if (!_attachType.isHidden()) _attachType.hideStart(); + if (!_emojiPan.isHidden()) _emojiPan.hideStart(); + + _field.setFocus(); +} + +void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption, UserData *bot) { + if (!_history || !photo || !canSendMessages(_peer)) return; + + App::main()->readServerHistory(_history, false); + fastShowAtEnd(_history); + + uint64 randomId = MTP::nonce(); + FullMsgId newId(_channel, clientMsgId()); + + bool lastKeyboardUsed = lastForceReplyReplied(); + + bool out = !_peer->isSelf(), unread = !_peer->isSelf(); + int32 flags = newMessageFlags(_peer) | MTPDmessage::flag_media; // unread, out + int32 sendFlags = 0; + if (replyToId()) { + flags |= MTPDmessage::flag_reply_to_msg_id; + sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id; + } + bool fromChannelName = _peer->isChannel() && !_peer->isMegagroup() && _peer->asChannel()->canPublish() && (_peer->asChannel()->isBroadcast() || _broadcast.checked()); + if (fromChannelName) { + sendFlags |= MTPmessages_SendMedia::flag_broadcast; + } else { + flags |= MTPDmessage::flag_from_id; + } + _history->addNewPhoto(newId.msg, flags, bot ? peerToUser(bot->id) : 0, replyToId(), date(MTP_int(unixtime())), fromChannelName ? 0 : MTP::authedId(), photo, caption); + + _history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), _peer->input, MTP_int(replyToId()), MTP_inputMediaPhoto(MTP_inputPhoto(MTP_long(photo->id), MTP_long(photo->access)), MTP_string(caption)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId); + App::main()->finishForwarding(_history, _broadcast.checked()); + cancelReply(lastKeyboardUsed); App::historyRegRandom(randomId, newId); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 8c9cac06e7..4b1619702c 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -638,6 +638,8 @@ public slots: void onFieldTabbed(); void onStickerSend(DocumentData *sticker); + void onPhotoSend(PhotoData *photo); + void onInlineResultSend(InlineResult *result, UserData *bot); void onVisibleChanged(); @@ -679,6 +681,9 @@ private: IconedButton _replyForwardPreviewCancel; void updateReplyToName(); + void sendExistingDocument(DocumentData *doc, const QString &caption, UserData *bot); + void sendExistingPhoto(PhotoData *photo, const QString &caption, UserData *bot); + void drawField(Painter &p); void drawRecordButton(Painter &p); void drawRecording(Painter &p); diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index c9abcbd79c..9b84b33a03 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -1314,7 +1314,7 @@ void LayoutInlineItem::preload() { _result->photo->thumb->load(); } else if (_result->doc) { _result->doc->thumb->load(); - } else if (!_result->thumb_url.isEmpty()) { + } else if (!_result->thumb->isNull()) { _result->thumb->load(); } } else if (_doc) { @@ -1324,6 +1324,12 @@ void LayoutInlineItem::preload() { } } +void LayoutInlineItem::update() { + if (_position >= 0) { + Ui::repaintInlineItem(this); + } +} + LayoutInlineGif::LayoutInlineGif(InlineResult *result, DocumentData *doc, bool saved) : LayoutInlineItem(result, doc, 0) , _state(0) , _gif(0) @@ -1365,7 +1371,7 @@ void DeleteSavedGifLink::onClick(Qt::MouseButton button) const { } void LayoutInlineGif::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { - content_automaticLoad(); +// content_automaticLoad(); bool loaded = content_loaded(), loading = content_loading(), displayLoading = content_displayLoading(); if (loaded && !gif() && _gif != BadClipReader) { @@ -1394,7 +1400,11 @@ void LayoutInlineGif::paint(Painter &p, const QRect &clip, uint32 selection, con p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, ctx->paused ? 0 : context->ms)); } else { prepareThumb(_width, height, frame); - p.drawPixmap(r.topLeft(), _thumb); + if (_thumb.isNull()) { + p.fillRect(r, st::overviewPhotoBg); + } else { + p.drawPixmap(r.topLeft(), _thumb); + } } if (radial || (!_gif && !loaded && !loading) || (_gif == BadClipReader)) { @@ -1468,7 +1478,8 @@ void LayoutInlineGif::linkOver(const TextLinkPtr &link) { void LayoutInlineGif::linkOut(const TextLinkPtr &link) { if (_delete && link == _delete) { if (_state & StateDeleteOver) { - EnsureAnimation(_a_deleteOver, 1, func(this, &LayoutInlineGif::update)); + update(); + EnsureAnimation(_a_deleteOver, 1, func(this, &LayoutInlineItem::update)); _state &= ~StateDeleteOver; _a_deleteOver.start(0, st::stickersRowDuration); } @@ -1477,7 +1488,7 @@ void LayoutInlineGif::linkOut(const TextLinkPtr &link) { if (!content_loaded()) { ensureAnimation(); if (_state & StateOver) { - EnsureAnimation(_animation->_a_over, 1, func(this, &LayoutInlineGif::update)); + EnsureAnimation(_animation->_a_over, 1, func(this, &LayoutInlineItem::update)); _animation->_a_over.start(0, st::stickersRowDuration); } } @@ -1513,6 +1524,7 @@ QSize LayoutInlineGif::countFrameSize() const { } LayoutInlineGif::~LayoutInlineGif() { + if (gif()) deleteAndMark(_gif); deleteAndMark(_animation); } @@ -1591,12 +1603,6 @@ void LayoutInlineGif::clipCallback(ClipReaderNotification notification) { } } -void LayoutInlineGif::update() { - if (_position >= 0) { - Ui::repaintInlineItem(this); - } -} - int32 LayoutInlineGif::content_width() const { DocumentData *doc = _doc ? _doc : (_result ? _result->doc : 0); if (doc) { @@ -1674,3 +1680,127 @@ QByteArray LayoutInlineGif::content_data() const { DocumentData *doc = _doc ? _doc : (_result ? _result->doc : 0); return doc ? doc->data() : _result->data(); } + +LayoutInlinePhoto::LayoutInlinePhoto(InlineResult *result, PhotoData *photo) : LayoutInlineItem(result, 0, photo) +, _send(new SendInlineItemLink()) +, _thumbLoaded(false) { +} + +void LayoutInlinePhoto::initDimensions() { + int32 w = content_width(), h = content_height(); + if (w <= 0 || h <= 0) { + _maxw = 0; + } else { + w = w * st::inlineMediaHeight / h; + _maxw = qMax(w, int32(st::inlineResultsMinWidth)); + } + _minh = st::inlineMediaHeight + st::inlineResultsSkip; +} + +void LayoutInlinePhoto::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + bool loaded = content_loaded(); + + int32 height = st::inlineMediaHeight; + QSize frame = countFrameSize(); + + QRect r(0, 0, _width, height); + + prepareThumb(_width, height, frame); + if (_thumb.isNull()) { + p.fillRect(r, st::overviewPhotoBg); + } else { + p.drawPixmap(r.topLeft(), _thumb); + } +} + +void LayoutInlinePhoto::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const { + if (x >= 0 && x < _width && y >= 0 && y < st::inlineMediaHeight) { + link = _send; + } +} + +QSize LayoutInlinePhoto::countFrameSize() const { + int32 framew = content_width(), frameh = content_height(), height = st::inlineMediaHeight; + if (framew * height > frameh * _width) { + if (framew < st::maxStickerSize || frameh > height) { + if (frameh > height || (framew * height / frameh) <= st::maxStickerSize) { + framew = framew * height / frameh; + frameh = height; + } else { + frameh = int32(frameh * st::maxStickerSize) / framew; + framew = st::maxStickerSize; + } + } + } else { + if (frameh < st::maxStickerSize || framew > _width) { + if (framew > _width || (frameh * _width / framew) <= st::maxStickerSize) { + frameh = frameh * _width / framew; + framew = _width; + } else { + framew = int32(framew * st::maxStickerSize) / frameh; + frameh = st::maxStickerSize; + } + } + } + return QSize(framew, frameh); +} + +void LayoutInlinePhoto::prepareThumb(int32 width, int32 height, const QSize &frame) const { + if (_photo) { + if (_photo->medium->loaded()) { + if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { + _thumb = _photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + } + _thumbLoaded = true; + } else { + if (_photo->thumb->loaded()) { + if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { + _thumb = _photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + } + } + _photo->medium->load(); + } + } else { + if (_result->thumb->loaded()) { + if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { + _thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + } + } else { + _result->thumb->load(); + } + } +} + +int32 LayoutInlinePhoto::content_width() const { + PhotoData *photo = _photo ? _photo : (_result ? _result->photo : 0); + if (photo) { + return photo->full->width(); + } else if (_result) { + return _result->width; + } + return 0; +} + +int32 LayoutInlinePhoto::content_height() const { + PhotoData *photo = _photo ? _photo : (_result ? _result->photo : 0); + if (photo) { + return photo->full->height(); + } else if (_result) { + return _result->height; + } + return 0; +} + +bool LayoutInlinePhoto::content_loaded() const { + PhotoData *photo = _photo ? _photo : (_result ? _result->photo : 0); + return photo ? photo->loaded() : _result->loaded(); +} + +void LayoutInlinePhoto::content_forget() { + PhotoData *photo = _photo ? _photo : (_result ? _result->photo : 0); + if (photo) { + photo->forget(); + } else { + _result->forget(); + } +} diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 2f9c092603..74150081b2 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -502,6 +502,8 @@ public: PhotoData *photo() const; void preload(); + void update(); + protected: InlineResult *_result; DocumentData *_doc; @@ -576,7 +578,7 @@ private: bool gif() const { return (!_gif || _gif == BadClipReader) ? false : true; } - QPixmap _thumb; + mutable QPixmap _thumb; void prepareThumb(int32 width, int32 height, const QSize &frame) const; void ensureAnimation() const; @@ -584,7 +586,6 @@ private: void step_radial(uint64 ms, bool timer); void clipCallback(ClipReaderNotification notification); - void update(); struct AnimationData { AnimationData(AnimationCreator creator) @@ -599,3 +600,32 @@ private: mutable FloatAnimation _a_deleteOver; }; + +class LayoutInlinePhoto : public LayoutInlineItem { +public: + LayoutInlinePhoto(InlineResult *result, PhotoData *photo); + + virtual void initDimensions(); + + virtual bool fullLine() const { + return false; + } + + virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const; + virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const; + +private: + QSize countFrameSize() const; + + int32 content_width() const; + int32 content_height() const; + bool content_loaded() const; + void content_forget(); + + TextLinkPtr _send; + + mutable QPixmap _thumb; + mutable bool _thumbLoaded; + void prepareThumb(int32 width, int32 height, const QSize &frame) const; + +}; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 790b48b5eb..ff40b4441b 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -2576,6 +2576,15 @@ namespace Local { return _stickerImagesMap.constFind(location) != _stickerImagesMap.cend(); } + void copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation) { + StorageMap::const_iterator i = _stickerImagesMap.constFind(oldLocation); + if (i != _stickerImagesMap.cend()) { + _stickerImagesMap.insert(newLocation, i.value()); + _mapChanged = true; + _writeMap(); + } + } + int32 hasStickers() { return _stickerImagesMap.size(); } diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 76c193ebea..2497f95542 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -130,6 +130,7 @@ namespace Local { void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true); TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader); bool willStickerImageLoad(const StorageKey &location); + void copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation); int32 hasStickers(); qint64 storageStickersSize(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 73bdd7967e..f51a5ebf41 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1888,6 +1888,24 @@ void MainWidget::documentLoadRetry() { if (document) document->save(failedFileName); } +void MainWidget::inlineResultLoadProgress(FileLoader *loader) { + //InlineResult *result = App::inlineResultFromLoader(loader); + //if (!result) return; + + //result->loaded(); + + //Ui::repaintInlineItem(); +} + +void MainWidget::inlineResultLoadFailed(FileLoader *loader, bool started) { + //InlineResult *result = App::inlineResultFromLoader(loader); + //if (!result) return; + + //result->loaded(); + + //Ui::repaintInlineItem(); +} + void MainWidget::audioMarkRead(AudioData *data) { const AudioItems &items(App::audioItems()); AudioItems::const_iterator i = items.constFind(data); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 40d29b7b86..78e92e1649 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -450,6 +450,8 @@ public slots: void documentLoadFailed(FileLoader *loader, bool started); void documentLoadRetry(); void documentPlayProgress(const SongMsgId &songId); + void inlineResultLoadProgress(FileLoader *loader); + void inlineResultLoadFailed(FileLoader *loader, bool started); void hidePlayer(); void dialogsCancelled(); diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp index 59ecebcef0..47d414a90b 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp @@ -57,7 +57,7 @@ namespace { WebLoadMainManager *_webLoadMainManager = 0; } -FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadFromCloudSetting fromCloud, bool autoLoading) +FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading) : _prev(0) , _next(0) , _priority(0) @@ -67,7 +67,7 @@ FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationT , _complete(false) , _localStatus(LocalNotTried) , _fileIsOpen(false) -, _toCache(LoadToCacheAsWell) +, _toCache(toCache) , _fromCloud(fromCloud) , _size(size) , _type(mtpc_storage_fileUnknown) @@ -339,7 +339,7 @@ void FileLoader::startLoading(bool loadFirst, bool prior) { } mtpFileLoader::mtpFileLoader(const StorageImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading) -: FileLoader(QString(), size, UnknownFileLocation, fromCloud, autoLoading) +: FileLoader(QString(), size, UnknownFileLocation, LoadToCacheAsWell, fromCloud, autoLoading) , _lastComplete(false) , _skippedBytes(0) , _nextRequestOffset(0) @@ -355,7 +355,7 @@ mtpFileLoader::mtpFileLoader(const StorageImageLocation *location, int32 size, L } mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, LocationType type, const QString &to, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading) -: FileLoader(to, size, type, fromCloud, autoLoading) +: FileLoader(to, size, type, toCache, fromCloud, autoLoading) , _lastComplete(false) , _skippedBytes(0) , _nextRequestOffset(0) @@ -566,7 +566,7 @@ mtpFileLoader::~mtpFileLoader() { } webFileLoader::webFileLoader(const QString &url, const QString &to, LoadFromCloudSetting fromCloud, bool autoLoading) -: FileLoader(QString(), 0, UnknownFileLocation, fromCloud, autoLoading) +: FileLoader(QString(), 0, UnknownFileLocation, LoadToCacheAsWell, fromCloud, autoLoading) , _url(url) , _requestSent(false) , _already(0) { @@ -835,6 +835,8 @@ void WebLoadManager::onFailed(QNetworkReply *reply) { webFileLoaderPrivate *loader = j.value(); _replies.erase(j); + LOG(("Network Error: Failed to request '%1', error %2 (%3)").arg(QString::fromLatin1(loader->_url.toEncoded())).arg(int(reply->error())).arg(reply->errorString())); + if (!handleReplyResult(loader, WebReplyProcessError)) { _loaders.remove(loader); delete loader; diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.h b/Telegram/SourceFiles/mtproto/mtpFileLoader.h index dd72712a9a..e181cacf3a 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.h +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.h @@ -126,7 +126,7 @@ class FileLoader : public QObject { public: - FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadFromCloudSetting fromCloud, bool autoLoading); + FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting, LoadFromCloudSetting fromCloud, bool autoLoading); bool done() const { return _complete; } diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 51e12ef020..68166bbaaf 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -1514,8 +1514,10 @@ void DocumentData::setattributes(const QVector &attributes type = StickerDocument; StickerData *sticker = new StickerData(); _additional = sticker; - sticker->alt = qs(d.valt); - sticker->set = d.vstickerset; + } + if (sticker()) { + sticker()->alt = qs(d.valt); + sticker()->set = d.vstickerset; } } break; case mtpc_documentAttributeVideo: { @@ -1528,12 +1530,16 @@ void DocumentData::setattributes(const QVector &attributes } break; case mtpc_documentAttributeAudio: { const MTPDdocumentAttributeAudio &d(attributes[i].c_documentAttributeAudio()); - type = SongDocument; - SongData *song = new SongData(); - _additional = song; - song->duration = d.vduration.v; - song->title = qs(d.vtitle); - song->performer = qs(d.vperformer); + if (type == FileDocument) { + type = SongDocument; + SongData *song = new SongData(); + _additional = song; + } + if (song()) { + song()->duration = d.vduration.v; + song()->title = qs(d.vtitle); + song()->performer = qs(d.vperformer); + } } break; case mtpc_documentAttributeFilename: name = qs(attributes[i].c_documentAttributeFilename().vfile_name); break; } @@ -2034,8 +2040,53 @@ void ImageLinkData::load() { manager.getData(this); } -void InlineResult::automaticLoadGif() const { +void InlineResult::automaticLoadGif() { + if (loaded() || type != qstr("gif") || (content_type != qstr("video/mp4") && content_type != "image/gif")) return; + if (_loader != CancelledWebFileLoader) { + // if load at least anywhere + bool loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups); + saveFile(QString(), loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true); + } +} + +void InlineResult::saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading) { + if (loaded()) { + return; + } + + if (_loader == CancelledWebFileLoader) _loader = 0; + if (_loader) { + if (!_loader->setFileName(toFile)) { + cancelFile(); + _loader = 0; + } + } + + if (_loader) { + if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud(); + } else { + _loader = new webFileLoader(content_url, toFile, fromCloud, autoLoading); + App::regInlineResultLoader(_loader, this); + + _loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(inlineResultLoadProgress(FileLoader*))); + _loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(inlineResultLoadFailed(FileLoader*,bool))); + _loader->start(); + } +} + +void InlineResult::cancelFile() { + if (!loading()) return; + + App::unregInlineResultLoader(_loader); + + webFileLoader *l = _loader; + _loader = CancelledWebFileLoader; + if (l) { + l->cancel(); + l->deleteLater(); + l->stop(); + } } QByteArray InlineResult::data() const { @@ -2043,22 +2094,43 @@ QByteArray InlineResult::data() const { } bool InlineResult::loading() const { - return false; + return _loader && _loader != CancelledWebFileLoader; } bool InlineResult::loaded() const { - return false; + if (loading() && _loader->done()) { + App::unregInlineResultLoader(_loader); + if (_loader->fileType() == mtpc_storage_fileUnknown) { + _loader->deleteLater(); + _loader->stop(); + _loader = CancelledWebFileLoader; + } else { + InlineResult *that = const_cast(this); + that->_data = _loader->bytes(); + + _loader->deleteLater(); + _loader->stop(); + _loader = 0; + } + } + return !_data.isEmpty(); } bool InlineResult::displayLoading() const { - return false; + return loading() ? (!_loader->loadingLocal() || !_loader->autoLoading()) : false; } void InlineResult::forget() { + thumb->forget(); + _data.clear(); } float64 InlineResult::progress() const { - return 0.; + return loading() ? _loader->currentProgress() : (loaded() ? 1 : 0); return false; +} + +InlineResult::~InlineResult() { + cancelFile(); } void PeerLink::onClick(Qt::MouseButton button) const { diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index e94c6a3d5f..e190ce17f6 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -1346,7 +1346,8 @@ public: , width(0) , height(0) , duration(0) - , noWebPage(false) { + , noWebPage(false) + , _loader(0) { } uint64 queryId; QString id, type; @@ -1362,7 +1363,11 @@ public: QString caption; // if message.isEmpty() use botContextMessageMediaAuto ImagePtr thumb; - void automaticLoadGif() const; + + void automaticLoadGif(); + void saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading); + void cancelFile(); + QByteArray data() const; bool loading() const; bool loaded() const; @@ -1370,8 +1375,11 @@ public: void forget(); float64 progress() const; + ~InlineResult(); + private: QByteArray _data; + mutable webFileLoader *_loader; }; typedef QList InlineResults; diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index 9c495102a6..e40a8d1dc5 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -556,19 +556,19 @@ template inline FunctionCreator func(R(*method)()) { return FunctionCreator(new WrappedFunction(method)); } -template +template class ObjectFunction : public FunctionImplementation { public: - typedef R(O::*Method)(); + typedef R(I::*Method)(); ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {} virtual R call() { return (_obj->*_method)(); } private: O *_obj; Method _method; }; -template -inline FunctionCreator func(O *obj, R(O::*method)()) { - return FunctionCreator(new ObjectFunction(obj, method)); +template +inline FunctionCreator func(O *obj, R(I::*method)()) { + return FunctionCreator(new ObjectFunction(obj, method)); } template @@ -625,19 +625,19 @@ template inline Function1Creator func(R(*method)(A1)) { return Function1Creator(new WrappedFunction1(method)); } -template +template class ObjectFunction1 : public Function1Implementation { public: - typedef R(O::*Method)(A1); + typedef R(I::*Method)(A1); ObjectFunction1(O *obj, Method method) : _obj(obj), _method(method) {} virtual R call(A1 a1) { return (_obj->*_method)(a1); } private: O *_obj; Method _method; }; -template -Function1Creator func(O *obj, R(O::*method)(A1)) { - return Function1Creator(new ObjectFunction1(obj, method)); +template +Function1Creator func(O *obj, R(I::*method)(A1)) { + return Function1Creator(new ObjectFunction1(obj, method)); } template @@ -695,17 +695,17 @@ Function2Creator func(R(*method)(A1, A2)) { return Function2Creator(new WrappedFunction2(method)); } -template +template class ObjectFunction2 : public Function2Implementation { public: - typedef R(O::*Method)(A1, A2); + typedef R(I::*Method)(A1, A2); ObjectFunction2(O *obj, Method method) : _obj(obj), _method(method) {} virtual R call(A1 a1, A2 a2) { return (_obj->*_method)(a1, a2); } private: O *_obj; Method _method; }; -template -Function2Creator func(O *obj, R(O::*method)(A1, A2)) { - return Function2Creator(new ObjectFunction2(obj, method)); +template +Function2Creator func(O *obj, R(I::*method)(A1, A2)) { + return Function2Creator(new ObjectFunction2(obj, method)); }