moved context bots to emojipan, fixed webpage thumb image size

This commit is contained in:
John Preston 2015-12-30 08:15:22 +08:00
parent 38ea16fea4
commit 96a698a4dc
5 changed files with 220 additions and 233 deletions

View File

@ -2254,7 +2254,9 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
, s_scroll(this, st::emojiScroll)
, s_inner()
, s_switch(&s_scroll, false)
, _removingSetId(0) {
, _removingSetId(0)
, _contextBot(0)
, _contextRequestId(0) {
setFocusPolicy(Qt::NoFocus);
e_scroll.setFocusPolicy(Qt::NoFocus);
e_scroll.viewport()->setFocusPolicy(Qt::NoFocus);
@ -2319,6 +2321,10 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
connect(&e_inner, SIGNAL(saveConfigDelayed(int32)), this, SLOT(onSaveConfigDelayed(int32)));
connect(&s_inner, SIGNAL(saveConfigDelayed(int32)), this, SLOT(onSaveConfigDelayed(int32)));
// context bots
_contextRequestTimer.setSingleShot(true);
connect(&_contextRequestTimer, SIGNAL(timeout()), this, SLOT(onContextRequest()));
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
}
@ -3159,12 +3165,134 @@ void EmojiPan::onDelayedHide() {
_removingSetId = 0;
}
MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, ContextRows *crows)
void EmojiPan::clearContextResults() {
if (_contextRequestId) MTP::cancel(_contextRequestId);
_contextRequestId = 0;
_contextQuery = _contextNextQuery = _contextNextOffset = QString();
_contextBot = 0;
_contextCache.clear();
}
void EmojiPan::contextResultsDone(const MTPmessages_BotResults &result) {
_contextRequestId = 0;
ContextCache::iterator it = _contextCache.find(_contextQuery);
bool adding = (it != _contextCache.cend());
if (result.type() == mtpc_messages_botResults) {
const MTPDmessages_botResults &d(result.c_messages_botResults());
const QVector<MTPBotContextResult> &v(d.vresults.c_vector().v);
uint64 queryId(d.vquery_id.v);
if (!adding) {
it = _contextCache.insert(_contextQuery, ContextCacheEntry());
}
it->nextOffset = v.isEmpty() ? QString() : qs(d.vnext_offset);
int32 count = v.size();
if (count) {
it->results.reserve(it->results.size() + count);
}
for (int32 i = 0; i < count; ++i) {
ContextResult result(queryId);
const MTPBotContextMessage *message = 0;
switch (v.at(i).type()) {
case mtpc_botContextMediaResultPhoto: {
const MTPDbotContextMediaResultPhoto &r(v.at(i).c_botContextMediaResultPhoto());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.photo = App::feedPhoto(r.vphoto);
message = &r.vsend_message;
} break;
case mtpc_botContextMediaResultDocument: {
const MTPDbotContextMediaResultDocument &r(v.at(i).c_botContextMediaResultDocument());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.doc = App::feedDocument(r.vdocument);
message = &r.vsend_message;
} break;
case mtpc_botContextResult: {
const MTPDbotContextResult &r(v.at(i).c_botContextResult());
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);
message = &r.vsend_message;
} break;
}
bool badAttachment = (!result.photo || result.photo->access) && (!result.doc || result.doc->access);
bool canSend = (result.photo || result.doc || !result.message.isEmpty());
if (!result.type.isEmpty() && !badAttachment && !canSend) {
it->results.push_back(result);
}
}
} else if (adding) {
it->results.clear();
it->nextOffset = QString();
}
refreshContextRows(!adding);
}
bool EmojiPan::contextResultsFail(const RPCError &error) {
if (mtpIsFlood(error)) return false;
_contextRequestId = 0;
return true;
}
void EmojiPan::showContextResults(UserData *bot, QString query) {
bool force = false;
if (bot != _contextBot) {
if (!isHidden()) hideStart();
clearContextResults();
_contextBot = bot;
force = true;
}
if (_contextRequestId) {
MTP::cancel(_contextRequestId);
_contextRequestId = 0;
}
if (_contextQuery != query || force) {
if (_contextCache.contains(_contextQuery)) {
refreshContextRows(true);
} else {
_contextNextQuery = _contextQuery;
_contextRequestTimer.start(ContextBotRequestDelay);
}
}
}
void EmojiPan::onContextRequest() {
if (_contextRequestId) return;
_contextQuery = _contextNextQuery;
QString nextOffset;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i != _contextCache.cend()) {
nextOffset = i->nextOffset;
if (nextOffset.isEmpty()) return;
}
_contextRequestId = MTP::send(MTPmessages_GetContextBotResults(_contextBot->inputUser, MTP_string(_contextQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::contextResultsDone), rpcFail(&EmojiPan::contextResultsFail));
}
void EmojiPan::refreshContextRows(bool toDown) {
bool clear = true;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i == _contextCache.cend()) {
clear = !i->results.isEmpty();
_contextNextOffset = i->nextOffset;
}
}
MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows)
: _parent(parent)
, _mrows(mrows)
, _hrows(hrows)
, _brows(brows)
, _crows(crows)
, _sel(-1)
, _mouseSel(false)
, _overDelete(false) {
@ -3422,9 +3550,7 @@ void MentionsInner::onParentGeometryChanged() {
MentionsDropdown::MentionsDropdown(QWidget *parent) : TWidget(parent)
, _scroll(this, st::mentionScroll)
, _inner(this, &_mrows, &_hrows, &_brows, &_crows)
, _contextBot(0)
, _contextRequestId(0)
, _inner(this, &_mrows, &_hrows, &_brows)
, _chat(0)
, _user(0)
, _channel(0)
@ -3437,9 +3563,6 @@ MentionsDropdown::MentionsDropdown(QWidget *parent) : TWidget(parent)
connect(&_inner, SIGNAL(chosen(QString)), this, SIGNAL(chosen(QString)));
connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
_contextRequestTimer.setSingleShot(true);
connect(&_contextRequestTimer, SIGNAL(timeout()), this, SLOT(onContextRequest()));
connect(App::wnd(), SIGNAL(imageLoaded()), &_inner, SLOT(update()));
setFocusPolicy(Qt::NoFocus);
@ -3470,137 +3593,7 @@ void MentionsDropdown::paintEvent(QPaintEvent *e) {
}
void MentionsDropdown::clearContextResults() {
if (_contextRequestId) MTP::cancel(_contextRequestId);
_contextRequestId = 0;
_contextQuery = _contextNextQuery = _contextNextOffset = QString();
_contextBot = 0;
_contextCache.clear();
_crows.clear();
}
void MentionsDropdown::contextResultsDone(const MTPmessages_BotResults &result) {
_contextRequestId = 0;
ContextCache::iterator it = _contextCache.find(_contextQuery);
bool adding = (it != _contextCache.cend());
if (result.type() == mtpc_messages_botResults) {
const MTPDmessages_botResults &d(result.c_messages_botResults());
const QVector<MTPBotContextResult> &v(d.vresults.c_vector().v);
uint64 queryId(d.vquery_id.v);
if (!adding) {
it = _contextCache.insert(_contextQuery, ContextCacheEntry());
}
it->nextOffset = v.isEmpty() ? QString() : qs(d.vnext_offset);
int32 count = v.size();
if (count) {
it->results.reserve(it->results.size() + count);
}
for (int32 i = 0; i < count; ++i) {
ContextResult result(queryId);
const MTPBotContextMessage *message = 0;
switch (v.at(i).type()) {
case mtpc_botContextMediaResultPhoto: {
const MTPDbotContextMediaResultPhoto &r(v.at(i).c_botContextMediaResultPhoto());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.photo = App::feedPhoto(r.vphoto);
message = &r.vsend_message;
} break;
case mtpc_botContextMediaResultDocument: {
const MTPDbotContextMediaResultDocument &r(v.at(i).c_botContextMediaResultDocument());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.doc = App::feedDocument(r.vdocument);
message = &r.vsend_message;
} break;
case mtpc_botContextResult: {
const MTPDbotContextResult &r(v.at(i).c_botContextResult());
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);
message = &r.vsend_message;
} break;
}
bool badAttachment = (!result.photo || result.photo->access) && (!result.doc || result.doc->access);
bool canSend = (result.photo || result.doc || !result.message.isEmpty());
if (!result.type.isEmpty() && !badAttachment && !canSend) {
it->results.push_back(result);
}
}
} else if (adding) {
it->results.clear();
it->nextOffset = QString();
}
refreshContextRows(!adding);
}
bool MentionsDropdown::contextResultsFail(const RPCError &error) {
if (mtpIsFlood(error)) return false;
_contextRequestId = 0;
return true;
}
void MentionsDropdown::showContextResults(UserData *bot, QString query) {
bool force = false;
if (bot != _contextBot) {
if (!isHidden()) hideStart();
clearContextResults();
_contextBot = bot;
force = true;
}
if (_contextRequestId) {
MTP::cancel(_contextRequestId);
_contextRequestId = 0;
}
if (_contextQuery != query || force) {
if (_contextCache.contains(_contextQuery)) {
refreshContextRows(true);
} else {
_contextNextQuery = _contextQuery;
_contextRequestTimer.start(ContextBotRequestDelay);
}
}
}
void MentionsDropdown::onContextRequest() {
if (_contextRequestId) return;
_contextQuery = _contextNextQuery;
QString nextOffset;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i != _contextCache.cend()) {
nextOffset = i->nextOffset;
if (nextOffset.isEmpty()) return;
}
_contextRequestId = MTP::send(MTPmessages_GetContextBotResults(_contextBot->inputUser, MTP_string(_contextQuery), MTP_string(nextOffset)), rpcDone(&MentionsDropdown::contextResultsDone), rpcFail(&MentionsDropdown::contextResultsFail));
}
void MentionsDropdown::refreshContextRows(bool toDown) {
bool clear = true;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i == _contextCache.cend()) {
clear = !i->results.isEmpty();
_contextNextOffset = i->nextOffset;
}
rowsUpdated(MentionRows(), HashtagRows(), BotCommandRows(), clear ? ContextRows() : _crows, toDown);
}
void MentionsDropdown::showFiltered(PeerData *peer, QString start) {
if (_contextBot) {
clearContextResults();
}
_chat = peer->asChat();
_user = peer->asUser();
_channel = peer->asChannel();
@ -3620,8 +3613,6 @@ bool MentionsDropdown::clearFilteredBotCommands() {
}
void MentionsDropdown::updateFiltered(bool toDown) {
clearContextResults();
int32 now = unixtime();
MentionRows rows;
HashtagRows hrows;
@ -3743,23 +3734,21 @@ void MentionsDropdown::updateFiltered(bool toDown) {
}
}
}
rowsUpdated(rows, hrows, brows, ContextRows(), toDown);
rowsUpdated(rows, hrows, brows, toDown);
}
void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, const ContextRows &crows, bool toDown) {
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && crows.isEmpty()) {
void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown) {
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty()) {
if (!isHidden()) {
hideStart();
}
_mrows.clear();
_hrows.clear();
_brows.clear();
_crows.clear();
} else {
_mrows = mrows;
_hrows = hrows;
_brows = brows;
_crows = crows;
bool hidden = _hiding || isHidden();
if (hidden) {
show();
@ -3911,16 +3900,5 @@ bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
return QWidget::eventFilter(obj, e);
}
void MentionsDropdown::ui_repaintSavedGif(const LayoutSavedGif *layout) {
}
bool MentionsDropdown::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return false;
}
bool MentionsDropdown::ui_isGifBeingChosen() {
return false;
}
MentionsDropdown::~MentionsDropdown() {
}

View File

@ -491,7 +491,7 @@ protected:
};
class EmojiPan : public TWidget {
class EmojiPan : public TWidget, public RPCSender {
Q_OBJECT
public:
@ -524,6 +524,9 @@ public:
bool eventFilter(QObject *obj, QEvent *e);
void stickersInstalled(uint64 setId);
void showContextResults(UserData *bot, QString query);
void clearContextResults();
bool overlaps(const QRect &globalRect) {
if (isHidden() || !_cache.isNull()) return false;
@ -563,6 +566,8 @@ public slots:
void onSaveConfig();
void onSaveConfigDelayed(int32 delay);
void onContextRequest();
signals:
void emojiSelected(EmojiPtr emoji);
@ -633,12 +638,50 @@ private:
QTimer _saveConfigTimer;
// context bots
struct ContextResult {
ContextResult(uint64 queryId)
: queryId(queryId)
, doc(0)
, photo(0)
, width(0)
, height(0)
, duration(0)
, noWebPage(false) {
}
uint64 queryId;
QString id, type;
DocumentData *doc;
PhotoData *photo;
QString title, description, url, thumb_url;
QString content_type, content_url;
int32 width, height, duration;
QString message; // botContextMessageText
bool noWebPage;
EntitiesInText entities;
QString caption; // if message.isEmpty() use botContextMessageMediaAuto
};
struct ContextCacheEntry {
QString nextOffset;
QList<ContextResult> results;
};
typedef QMap<QString, ContextCacheEntry> ContextCache;
ContextCache _contextCache;
QTimer _contextRequestTimer;
void refreshContextRows(bool toDown);
UserData *_contextBot;
QString _contextQuery, _contextNextQuery, _contextNextOffset;
mtpRequestId _contextRequestId;
void contextResultsDone(const MTPmessages_BotResults &result);
bool contextResultsFail(const RPCError &error);
};
typedef QList<UserData*> MentionRows;
typedef QList<QString> HashtagRows;
typedef QList<QPair<UserData*, const BotCommand*> > BotCommandRows;
typedef QList<QString> ContextRows;
class MentionsDropdown;
class MentionsInner : public TWidget {
@ -646,7 +689,7 @@ class MentionsInner : public TWidget {
public:
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, ContextRows *crows);
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows);
void paintEvent(QPaintEvent *e);
@ -680,7 +723,6 @@ private:
MentionRows *_mrows;
HashtagRows *_hrows;
BotCommandRows *_brows;
ContextRows *_crows;
int32 _sel;
bool _mouseSel;
QPoint _mousePos;
@ -688,7 +730,7 @@ private:
bool _overDelete;
};
class MentionsDropdown : public TWidget, public RPCSender {
class MentionsDropdown : public TWidget {
Q_OBJECT
public:
@ -700,7 +742,6 @@ public:
void fastHide();
bool clearFilteredBotCommands();
void showContextResults(UserData *bot, QString query);
void showFiltered(PeerData *peer, QString start);
void updateFiltered(bool toDown = false);
void setBoundings(QRect boundings);
@ -723,11 +764,6 @@ public:
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
void clearContextResults();
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
~MentionsDropdown();
@ -741,7 +777,6 @@ public slots:
void hideFinish();
void showStart();
void onContextRequest();
private:
@ -751,51 +786,12 @@ private:
MentionRows _mrows;
HashtagRows _hrows;
BotCommandRows _brows;
ContextRows _crows;
struct ContextResult {
ContextResult(uint64 queryId)
: queryId(queryId)
, doc(0)
, photo(0)
, width(0)
, height(0)
, duration(0)
, noWebPage(false) {
}
uint64 queryId;
QString id, type;
DocumentData *doc;
PhotoData *photo;
QString title, description, url, thumb_url;
QString content_type, content_url;
int32 width, height, duration;
QString message; // botContextMessageText
bool noWebPage;
EntitiesInText entities;
QString caption; // if message.isEmpty() use botContextMessageMediaAuto
};
struct ContextCacheEntry {
QString nextOffset;
QList<ContextResult> results;
};
typedef QMap<QString, ContextCacheEntry> ContextCache;
ContextCache _contextCache;
QTimer _contextRequestTimer;
void refreshContextRows(bool toDown);
void rowsUpdated(const MentionRows &rows, const HashtagRows &hrows, const BotCommandRows &brows, const ContextRows &crows, bool toDown);
void rowsUpdated(const MentionRows &rows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown);
ScrollArea _scroll;
MentionsInner _inner;
UserData *_contextBot;
QString _contextQuery, _contextNextQuery, _contextNextOffset;
mtpRequestId _contextRequestId;
void contextResultsDone(const MTPmessages_BotResults &result);
bool contextResultsFail(const RPCError &error);
ChatData *_chat;
UserData *_user;
ChannelData *_channel;

View File

@ -258,21 +258,21 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&c
// check context bot query
const QString &text(getLastText());
int32 size = text.size();
int32 contextUsernameStart = 1, contextUsernameLength = 0, size = text.size();
if (size > 2 && text.at(0) == '@' && text.at(1).isLetter()) {
int32 usernameStart = 1, usernameLength = 1;
for (int32 i = usernameStart + 1, l = text.size(); i < l; ++i) {
contextUsernameLength = 1;
for (int32 i = contextUsernameStart + 1, l = text.size(); i < l; ++i) {
if (text.at(i).isLetterOrNumber() || text.at(i).unicode() == '_') {
++usernameLength;
++contextUsernameLength;
continue;
}
if (!text.at(i).isSpace()) {
usernameLength = 0;
contextUsernameLength = 0;
}
break;
}
if (usernameLength && usernameStart + usernameLength < text.size() && text.at(usernameStart + usernameLength).isSpace()) {
QStringRef username = text.midRef(usernameStart, usernameLength);
if (contextUsernameLength && contextUsernameStart + contextUsernameLength < text.size() && text.at(contextUsernameStart + contextUsernameLength).isSpace()) {
QStringRef username = text.midRef(contextUsernameStart, contextUsernameLength);
if (username != contextBotUsername) {
contextBotUsername = username.toString();
PeerData *peer = App::peerByName(contextBotUsername);
@ -291,14 +291,15 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&c
if (contextBot && (!contextBot->botInfo || contextBot->botInfo->contextPlaceholder.isEmpty())) {
contextBot = 0;
} else {
start = text.mid(usernameStart + usernameLength + 1);
start = text.mid(contextUsernameStart + contextUsernameLength + 1);
return;
}
} else {
contextBot = 0;
contextBotUsername = QString();
}
}
if (!contextUsernameLength) {
contextBot = 0;
contextBotUsername = QString();
}
// check mention / hashtag / bot command
QTextDocument *doc(document());

View File

@ -5386,11 +5386,18 @@ void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, const QRect &r,
_data->photo->medium->load(false, false);
bool full = _data->photo->medium->loaded();
QPixmap pix;
int32 pw = qMax(_pixw, int16(_lineHeight));
int32 pw = qMax(_pixw, int16(_lineHeight)), ph = _pixh;
int32 pixw = _pixw, pixh = articleThumbHeight(_data->photo, _pixw);
int32 maxw = convertScale(_data->photo->medium->width()), maxh = convertScale(_data->photo->medium->height());
if (pixw * ph != pixh * pw) {
float64 coef = (pixw * ph > pixh * pw) ? qMin(ph / float64(pixh), maxh / float64(pixh)) : qMin(pw / float64(pixw), maxw / float64(pixw));
pixh = qRound(pixh * coef);
pixw = qRound(pixw * coef);
}
if (full) {
pix = _data->photo->medium->pixSingle(_pixw, articleThumbHeight(_data->photo, _pixw), pw, _pixh);
pix = _data->photo->medium->pixSingle(pixw, pixh, pw, ph);
} else {
pix = _data->photo->thumb->pixBlurredSingle(_pixw, articleThumbHeight(_data->photo, _pixw), pw, _pixh);
pix = _data->photo->thumb->pixBlurredSingle(pixw, pixh, pw, ph);
}
p.drawPixmapLeft(lshift + width - pw, 0, _width, pix);
if (selected) {

View File

@ -5327,17 +5327,22 @@ void HistoryWidget::onCheckMentionDropdown() {
}
if (_contextBot) {
_attachMention.showContextResults(_contextBot, start);
} else if (!start.isEmpty()) {
if (start.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtags();
if (start.at(0) == '@' && _peer->isUser()) return;
if (start.at(0) == '/' && _peer->isUser() && !_peer->asUser()->botInfo) return;
_attachMention.showFiltered(_peer, start);
} else {
_emojiPan.showContextResults(_contextBot, start);
if (!_attachMention.isHidden()) {
_attachMention.hideStart();
}
_attachMention.clearContextResults();
} else {
_emojiPan.clearContextResults();
if (!start.isEmpty()) {
if (start.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtags();
if (start.at(0) == '@' && _peer->isUser()) return;
if (start.at(0) == '/' && _peer->isUser() && !_peer->asUser()->botInfo) return;
_attachMention.showFiltered(_peer, start);
} else {
if (!_attachMention.isHidden()) {
_attachMention.hideStart();
}
}
}
}
@ -5770,11 +5775,11 @@ void HistoryWidget::ui_repaintSavedGif(const LayoutSavedGif *layout) {
}
bool HistoryWidget::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return _emojiPan.ui_isSavedGifVisible(layout) || _attachMention.ui_isSavedGifVisible(layout);
return _emojiPan.ui_isSavedGifVisible(layout);
}
bool HistoryWidget::ui_isGifBeingChosen() {
return _emojiPan.ui_isGifBeingChosen() || _attachMention.ui_isGifBeingChosen();
return _emojiPan.ui_isGifBeingChosen();
}
void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {