From 38ea16fea4ca4d7f33172b5f0ca995abf6f5505f Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 30 Dec 2015 01:29:24 +0800 Subject: [PATCH] context bot requests sent from MentionsDropdown --- Telegram/SourceFiles/config.h | 1 + Telegram/SourceFiles/dropdown.cpp | 205 +++++++++++++++++++++---- Telegram/SourceFiles/dropdown.h | 59 ++++++- Telegram/SourceFiles/gui/animation.cpp | 1 - Telegram/SourceFiles/gui/images.cpp | 4 +- Telegram/SourceFiles/gui/text.cpp | 2 +- Telegram/SourceFiles/historywidget.cpp | 9 +- 7 files changed, 238 insertions(+), 43 deletions(-) diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 2f0b054749..f8e480215f 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -86,6 +86,7 @@ enum { ClipThreadsCount = 4, AverageGifSize = 320 * 240, WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it + ContextBotRequestDelay = 400, // wait 400ms before context bot realtime request AVBlockSize = 4096, // 4Kb for ffmpeg blocksize diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 2d0cae199e..7847397e3b 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -3159,7 +3159,15 @@ void EmojiPan::onDelayedHide() { _removingSetId = 0; } -MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *rows, HashtagRows *hrows, BotCommandRows *crows) : _parent(parent), _rows(rows), _hrows(hrows), _crows(crows), _sel(-1), _mouseSel(false), _overDelete(false) { +MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, ContextRows *crows) +: _parent(parent) +, _mrows(mrows) +, _hrows(hrows) +, _brows(brows) +, _crows(crows) +, _sel(-1) +, _mouseSel(false) +, _overDelete(false) { } void MentionsInner::paintEvent(QPaintEvent *e) { @@ -3171,7 +3179,7 @@ void MentionsInner::paintEvent(QPaintEvent *e) { int32 htagleft = st::btnAttachPhoto.width + st::taMsgField.textMrg.left() - st::lineWidth, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width; int32 from = qFloor(e->rect().top() / st::mentionHeight), to = qFloor(e->rect().bottom() / st::mentionHeight) + 1; - int32 last = _rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size(); + int32 last = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size(); bool hasUsername = _parent->filter().indexOf('@') > 1; for (int32 i = from; i < to; ++i) { if (i >= last) break; @@ -3183,8 +3191,8 @@ void MentionsInner::paintEvent(QPaintEvent *e) { if (!_hrows->isEmpty()) p.drawPixmap(QPoint(width() - st::notifyClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), App::sprite(), st::notifyClose.icon); } p.setPen(st::black->p); - if (!_rows->isEmpty()) { - UserData *user = _rows->at(i); + if (!_mrows->isEmpty()) { + UserData *user = _mrows->at(i); QString first = (_parent->filter().size() < 2) ? QString() : ('@' + user->username.mid(0, _parent->filter().size() - 1)), second = (_parent->filter().size() < 2) ? ('@' + user->username) : user->username.mid(_parent->filter().size() - 1); int32 firstwidth = st::mentionFont->width(first), secondwidth = st::mentionFont->width(second), unamewidth = firstwidth + secondwidth, namewidth = user->nameText.maxWidth(); if (mentionwidth < unamewidth + namewidth) { @@ -3235,9 +3243,9 @@ void MentionsInner::paintEvent(QPaintEvent *e) { p.drawText(htagleft + firstwidth, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, second); } } else { - UserData *user = _crows->at(i).first; + UserData *user = _brows->at(i).first; - const BotCommand *command = _crows->at(i).second; + const BotCommand *command = _brows->at(i).second; QString toHighlight = command->command; int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : ((_parent->channel() && _parent->channel()->isMegagroup()) ? _parent->channel()->mgInfo->botStatus : -1); if (hasUsername || botStatus == 0 || botStatus == 2) { @@ -3289,12 +3297,12 @@ void MentionsInner::mouseMoveEvent(QMouseEvent *e) { void MentionsInner::clearSel() { _mouseSel = _overDelete = false; - setSel((_rows->isEmpty() && _crows->isEmpty() && _hrows->isEmpty()) ? -1 : 0); + setSel((_mrows->isEmpty() && _brows->isEmpty() && _hrows->isEmpty()) ? -1 : 0); } bool MentionsInner::moveSel(int direction) { _mouseSel = false; - int32 maxSel = (_rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size()); + int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size()); if (_sel >= maxSel || _sel < 0) { if (direction < 0) { setSel(maxSel - 1, true); @@ -3317,16 +3325,16 @@ bool MentionsInner::select() { } QString MentionsInner::getSelected() const { - int32 maxSel = (_rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size()); + int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size()); if (_sel >= 0 && _sel < maxSel) { QString result; - if (!_rows->isEmpty()) { - result = '@' + _rows->at(_sel)->username; + if (!_mrows->isEmpty()) { + result = '@' + _mrows->at(_sel)->username; } else if (!_hrows->isEmpty()) { result = '#' + _hrows->at(_sel); } else { - UserData *user = _crows->at(_sel).first; - const BotCommand *command(_crows->at(_sel).second); + UserData *user = _brows->at(_sel).first; + const BotCommand *command(_brows->at(_sel).second); int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : ((_parent->channel() && _parent->channel()->isMegagroup()) ? _parent->channel()->mgInfo->botStatus : -1); if (botStatus == 0 || botStatus == 2 || _parent->filter().indexOf('@') > 1) { result = '/' + command->command + '@' + user->username; @@ -3385,7 +3393,7 @@ void MentionsInner::setSel(int sel, bool scroll) { if (_sel >= 0) update(0, _sel * st::mentionHeight, width(), st::mentionHeight); _sel = sel; if (_sel >= 0) update(0, _sel * st::mentionHeight, width(), st::mentionHeight); - int32 maxSel = _rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size(); + int32 maxSel = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size(); if (scroll && _sel >= 0 && _sel < maxSel) emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight); } @@ -3394,8 +3402,8 @@ void MentionsInner::onUpdateSelected(bool force) { if ((!force && !rect().contains(mouse)) || !_mouseSel) return; int w = width(), mouseY = mouse.y(); - _overDelete = _rows->isEmpty() && (mouse.x() >= w - st::mentionHeight); - int32 sel = mouseY / int32(st::mentionHeight), maxSel = _rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size(); + _overDelete = _mrows->isEmpty() && (mouse.x() >= w - st::mentionHeight); + int32 sel = mouseY / int32(st::mentionHeight), maxSel = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size(); if (sel < 0 || sel >= maxSel) { sel = -1; } @@ -3414,7 +3422,9 @@ void MentionsInner::onParentGeometryChanged() { MentionsDropdown::MentionsDropdown(QWidget *parent) : TWidget(parent) , _scroll(this, st::mentionScroll) -, _inner(this, &_rows, &_hrows, &_crows) +, _inner(this, &_mrows, &_hrows, &_brows, &_crows) +, _contextBot(0) +, _contextRequestId(0) , _chat(0) , _user(0) , _channel(0) @@ -3427,6 +3437,9 @@ 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); @@ -3457,11 +3470,137 @@ 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 &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(); @@ -3474,17 +3613,19 @@ void MentionsDropdown::showFiltered(PeerData *peer, QString start) { updateFiltered(toDown); } -bool MentionsDropdown::clearFilteredCommands() { - if (_crows.isEmpty()) return false; - _crows.clear(); +bool MentionsDropdown::clearFilteredBotCommands() { + if (_brows.isEmpty()) return false; + _brows.clear(); return true; } void MentionsDropdown::updateFiltered(bool toDown) { + clearContextResults(); + int32 now = unixtime(); MentionRows rows; HashtagRows hrows; - BotCommandRows crows; + BotCommandRows brows; if (_filter.at(0) == '@' && _chat) { QMultiMap ordered; rows.reserve(_chat->participants.isEmpty() ? _chat->lastAuthors.size() : _chat->participants.size()); @@ -3569,7 +3710,7 @@ void MentionsDropdown::updateFiltered(bool toDown) { } } if (cnt) { - crows.reserve(cnt); + brows.reserve(cnt); int32 botStatus = _chat ? _chat->botStatus : ((_channel && _channel->isMegagroup()) ? _channel->mgInfo->botStatus : -1); if (_chat) { for (MentionRows::const_iterator i = _chat->lastAuthors.cbegin(), e = _chat->lastAuthors.cend(); i != e; ++i) { @@ -3584,7 +3725,7 @@ void MentionsDropdown::updateFiltered(bool toDown) { QString toFilter = (hasUsername || botStatus == 0 || botStatus == 2) ? user->botInfo->commands.at(j).command + '@' + user->username : user->botInfo->commands.at(j).command; if (!toFilter.startsWith(_filter.midRef(1), Qt::CaseInsensitive)/* || toFilter.size() + 1 == _filter.size()*/) continue; } - crows.push_back(qMakePair(user, &user->botInfo->commands.at(j))); + brows.push_back(qMakePair(user, &user->botInfo->commands.at(j))); } } } @@ -3596,22 +3737,28 @@ void MentionsDropdown::updateFiltered(bool toDown) { QString toFilter = (hasUsername || botStatus == 0 || botStatus == 2) ? user->botInfo->commands.at(j).command + '@' + user->username : user->botInfo->commands.at(j).command; if (!toFilter.startsWith(_filter.midRef(1), Qt::CaseInsensitive)/* || toFilter.size() + 1 == _filter.size()*/) continue; } - crows.push_back(qMakePair(user, &user->botInfo->commands.at(j))); + brows.push_back(qMakePair(user, &user->botInfo->commands.at(j))); } } } } } - if (rows.isEmpty() && hrows.isEmpty() && crows.isEmpty()) { + rowsUpdated(rows, hrows, brows, ContextRows(), 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()) { if (!isHidden()) { hideStart(); } - _rows.clear(); + _mrows.clear(); _hrows.clear(); + _brows.clear(); _crows.clear(); } else { - _rows = rows; + _mrows = mrows; _hrows = hrows; + _brows = brows; _crows = crows; bool hidden = _hiding || isHidden(); if (hidden) { @@ -3635,7 +3782,7 @@ void MentionsDropdown::setBoundings(QRect boundings) { } void MentionsDropdown::recount(bool toDown) { - int32 h = (_rows.isEmpty() ? (_hrows.isEmpty() ? _crows.size() : _hrows.size()) : _rows.size()) * st::mentionHeight, oldst = _scroll.scrollTop(), st = oldst; + int32 h = (_mrows.isEmpty() ? (_hrows.isEmpty() ? _brows.size() : _hrows.size()) : _mrows.size()) * st::mentionHeight, oldst = _scroll.scrollTop(), st = oldst; if (_inner.height() != h) { // st += h - _inner.height(); diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h index d6baf235d7..e8f73e001a 100644 --- a/Telegram/SourceFiles/dropdown.h +++ b/Telegram/SourceFiles/dropdown.h @@ -638,6 +638,7 @@ private: typedef QList MentionRows; typedef QList HashtagRows; typedef QList > BotCommandRows; +typedef QList ContextRows; class MentionsDropdown; class MentionsInner : public TWidget { @@ -645,7 +646,7 @@ class MentionsInner : public TWidget { public: - MentionsInner(MentionsDropdown *parent, MentionRows *rows, HashtagRows *hrows, BotCommandRows *crows); + MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, ContextRows *crows); void paintEvent(QPaintEvent *e); @@ -676,9 +677,10 @@ private: void setSel(int sel, bool scroll = false); MentionsDropdown *_parent; - MentionRows *_rows; + MentionRows *_mrows; HashtagRows *_hrows; - BotCommandRows *_crows; + BotCommandRows *_brows; + ContextRows *_crows; int32 _sel; bool _mouseSel; QPoint _mousePos; @@ -686,7 +688,7 @@ private: bool _overDelete; }; -class MentionsDropdown : public TWidget { +class MentionsDropdown : public TWidget, public RPCSender { Q_OBJECT public: @@ -697,7 +699,7 @@ public: void fastHide(); - bool clearFilteredCommands(); + bool clearFilteredBotCommands(); void showContextResults(UserData *bot, QString query); void showFiltered(PeerData *peer, QString start); void updateFiltered(bool toDown = false); @@ -721,6 +723,7 @@ public: return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); } + void clearContextResults(); void ui_repaintSavedGif(const LayoutSavedGif *layout); bool ui_isSavedGifVisible(const LayoutSavedGif *layout); @@ -738,19 +741,61 @@ public slots: void hideFinish(); void showStart(); + void onContextRequest(); private: void recount(bool toDown = false); QPixmap _cache; - MentionRows _rows; + MentionRows _mrows; HashtagRows _hrows; - BotCommandRows _crows; + 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 results; + }; + typedef QMap 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); 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; diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp index c89ab7fa32..cb4413842e 100644 --- a/Telegram/SourceFiles/gui/animation.cpp +++ b/Telegram/SourceFiles/gui/animation.cpp @@ -573,7 +573,6 @@ public: for (int32 i = 0, l = _frame->height; i < l; ++i) { memcpy(d + i * dbpl, s + i * sbpl, bpl); } - } else { if ((_swsSize != toSize) || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) { _swsSize = toSize; diff --git a/Telegram/SourceFiles/gui/images.cpp b/Telegram/SourceFiles/gui/images.cpp index 034aef09f6..043c96f638 100644 --- a/Telegram/SourceFiles/gui/images.cpp +++ b/Telegram/SourceFiles/gui/images.cpp @@ -212,7 +212,7 @@ const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) co } uint64 k = 0LL; Sizes::const_iterator i = _sizesCache.constFind(k); - if (i == _sizesCache.cend() || i->width() != w || (h && i->height() != h)) { + if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) { if (i != _sizesCache.cend()) { globalAquiredSize -= int64(i->width()) * i->height() * 4; } @@ -237,7 +237,7 @@ const QPixmap &Image::pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 out } uint64 k = BlurredCacheSkip | 0LL; Sizes::const_iterator i = _sizesCache.constFind(k); - if (i == _sizesCache.cend() || i->width() != w || (h && i->height() != h)) { + if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) { if (i != _sizesCache.cend()) { globalAquiredSize -= int64(i->width()) * i->height() * 4; } diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index aec996a4d1..042783aded 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -36,7 +36,7 @@ namespace { const QRegularExpression _reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$")); const QRegularExpression _reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@")); const QRegularExpression _reHashtag(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[\\w]{2,64}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); - const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{5,32}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); + const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{3,32}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); const QRegularExpression _reBotCommand(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])/[A-Za-z_0-9]{1,64}(@[A-Za-z_0-9]{5,32})?([\\W]|$)")); const QRegularExpression _rePre(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(````?)[\\s\\S]+?(````?)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); const QRegularExpression _reCode(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(`)[^\\n]+?(`)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 91ebf85b48..47ea53a766 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3020,7 +3020,7 @@ void HistoryWidget::updateStickers() { void HistoryWidget::notify_botCommandsChanged(UserData *user) { if (_peer && (_peer == user || !_peer->isUser())) { - if (_attachMention.clearFilteredCommands()) { + if (_attachMention.clearFilteredBotCommands()) { onCheckMentionDropdown(); } } @@ -5333,8 +5333,11 @@ void HistoryWidget::onCheckMentionDropdown() { 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(); + } else { + if (!_attachMention.isHidden()) { + _attachMention.hideStart(); + } + _attachMention.clearContextResults(); } }