inline bots gif / photo preview / sending done

This commit is contained in:
John Preston 2015-12-31 13:34:43 +08:00
parent 14839e7afe
commit 5830e0f657
20 changed files with 757 additions and 210 deletions

View File

@ -113,6 +113,9 @@ namespace {
typedef QHash<PhotoData*, LastPhotosList::iterator> LastPhotosMap;
LastPhotosMap lastPhotosMap;
typedef QMap<FileLoader*, InlineResult*> 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<MTPDocumentAttribute>::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<MTPDocumentAttribute>::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);

View File

@ -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);

View File

@ -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) {

View File

@ -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<bool> _custom;
bool _showingSavedGifs, _showingInlineItems;
UserData *_inlineBot;
QString _inlineBotTitle;
uint64 _lastScrolled;
QTimer _updateInlineItems;
@ -436,7 +440,7 @@ private:
};
typedef QVector<InlineRow> InlineRows;
InlineRows _inlineRows;
void clearInlineRows();
void clearInlineRows(bool resultsDeleted);
typedef QMap<DocumentData*, LayoutInlineGif*> 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:

View File

@ -294,6 +294,8 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&i
start = text.mid(inlineUsernameStart + inlineUsernameLength + 1);
return;
}
} else {
inlineUsernameLength = 0;
}
}
if (!inlineUsernameLength) {

View File

@ -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 &currentTex
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);

View File

@ -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<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed);
void addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *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 &currentText);
@ -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();

View File

@ -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<uint64>();
QVector<MTPDocumentAttribute> 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<MTPDocumentAttribute>(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<MTPPhotoSize> 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<uint64>()), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(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<uint64>();
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<uint64>();
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);

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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;
}

View File

@ -1514,8 +1514,10 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &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<MTPDocumentAttribute> &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<InlineResult*>(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 {

View File

@ -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<InlineResult*> InlineResults;

View File

@ -556,19 +556,19 @@ template <typename R>
inline FunctionCreator<R> func(R(*method)()) {
return FunctionCreator<R>(new WrappedFunction<R>(method));
}
template <typename O, typename R>
template <typename O, typename I, typename R>
class ObjectFunction : public FunctionImplementation<R> {
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 <typename O, typename R>
inline FunctionCreator<R> func(O *obj, R(O::*method)()) {
return FunctionCreator<R>(new ObjectFunction<O, R>(obj, method));
template <typename O, typename I, typename R>
inline FunctionCreator<R> func(O *obj, R(I::*method)()) {
return FunctionCreator<R>(new ObjectFunction<O, I, R>(obj, method));
}
template <typename R, typename A1>
@ -625,19 +625,19 @@ template <typename R, typename A1>
inline Function1Creator<R, A1> func(R(*method)(A1)) {
return Function1Creator<R, A1>(new WrappedFunction1<R, A1>(method));
}
template <typename O, typename R, typename A1>
template <typename O, typename I, typename R, typename A1>
class ObjectFunction1 : public Function1Implementation<R, A1> {
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 <typename O, typename R, typename A1>
Function1Creator<R, A1> func(O *obj, R(O::*method)(A1)) {
return Function1Creator<R, A1>(new ObjectFunction1<O, R, A1>(obj, method));
template <typename O, typename I, typename R, typename A1>
Function1Creator<R, A1> func(O *obj, R(I::*method)(A1)) {
return Function1Creator<R, A1>(new ObjectFunction1<O, I, R, A1>(obj, method));
}
template <typename R, typename A1, typename A2>
@ -695,17 +695,17 @@ Function2Creator<R, A1, A2> func(R(*method)(A1, A2)) {
return Function2Creator<R, A1, A2>(new WrappedFunction2<R, A1, A2>(method));
}
template <typename O, typename R, typename A1, typename A2>
template <typename O, typename I, typename R, typename A1, typename A2>
class ObjectFunction2 : public Function2Implementation<R, A1, A2> {
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 <typename O, typename R, typename A1, typename A2>
Function2Creator<R, A1, A2> func(O *obj, R(O::*method)(A1, A2)) {
return Function2Creator<R, A1, A2>(new ObjectFunction2<O, R, A1, A2>(obj, method));
template <typename O, typename I, typename R, typename A1, typename A2>
Function2Creator<R, A1, A2> func(O *obj, R(I::*method)(A1, A2)) {
return Function2Creator<R, A1, A2>(new ObjectFunction2<O, I, R, A1, A2>(obj, method));
}