remembering last used inline bots, showing them in mentions dropdown, 9015006 beta

This commit is contained in:
John Preston 2016-01-01 22:48:32 +08:00
parent 85f46cef8c
commit cb2df51af6
15 changed files with 308 additions and 198 deletions

View file

@ -705,10 +705,11 @@ void Application::checkMapVersion() {
if (Local::oldMapVersion() < AppVersion) { if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion()) { if (Local::oldMapVersion()) {
QString versionFeatures; QString versionFeatures;
if (cDevVersion() && Local::oldMapVersion() < 9014) { if (cDevVersion() && Local::oldMapVersion() < 9016) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n\xe2\x80\x94 Click and hold on a sticker to preview it before sending\n\xe2\x80\x94 New context menu for chats in chats list\n\xe2\x80\x94 Support for all existing emoji");// .replace('@', qsl("@") + QChar(0x200D)); // versionFeatures = QString::fromUtf8("\xe2\x80\x94 Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n\xe2\x80\x94 Click and hold on a sticker to preview it before sending\n\xe2\x80\x94 New context menu for chats in chats list\n\xe2\x80\x94 Support for all existing emoji");// .replace('@', qsl("@") + QChar(0x200D));
versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
} else if (Local::oldMapVersion() < 9015) { } else if (Local::oldMapVersion() < 9015) {
// versionFeatures = lang(lng_new_version_text).trimmed(); versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
} else { } else {
versionFeatures = lang(lng_new_version_minor).trimmed(); versionFeatures = lang(lng_new_version_minor).trimmed();
} }

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
static const int32 AppVersion = 9015; static const int32 AppVersion = 9015;
static const wchar_t *AppVersionStr = L"0.9.15"; static const wchar_t *AppVersionStr = L"0.9.15";
static const bool DevVersion = false; static const bool DevVersion = false;
#define BETA_VERSION (9015005ULL) // just comment this line to build public version #define BETA_VERSION (9015006ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop"; static const wchar_t *AppName = L"Telegram Desktop";
@ -87,6 +87,7 @@ enum {
AverageGifSize = 320 * 240, AverageGifSize = 320 * 240,
WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it
InlineBotRequestDelay = 400, // wait 400ms before context bot realtime request InlineBotRequestDelay = 400, // wait 400ms before context bot realtime request
RecentInlineBotsLimit = 10,
AVBlockSize = 4096, // 4Kb for ffmpeg blocksize AVBlockSize = 4096, // 4Kb for ffmpeg blocksize

View file

@ -163,7 +163,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
PeerData *act = App::main()->activePeer(); PeerData *act = App::main()->activePeer();
MsgId actId = App::main()->activeMsgId(); MsgId actId = App::main()->activeMsgId();
for (; from < to; ++from) { for (; from < to; ++from) {
bool active = ((_filterResults[from]->history->peer == act) || (_filterResults[from]->history->peer->migrateTo() && _filterResults[from]->history->peer->migrateTo() == act)) && !actId; bool active = ((_filterResults[from]->history->peer == act) || (_filterResults[from]->history->peer->migrateTo() && _filterResults[from]->history->peer->migrateTo() == act)) && !actId;
bool selected = (from == _filteredSel) || (_filterResults[from]->history->peer == _menuPeer); bool selected = (from == _filteredSel) || (_filterResults[from]->history->peer == _menuPeer);
_filterResults[from]->paint(p, w, active, selected, paintingOther); _filterResults[from]->paint(p, w, active, selected, paintingOther);
p.translate(0, st::dlgHeight); p.translate(0, st::dlgHeight);
@ -872,7 +872,7 @@ void DialogsInner::onHashtagFilterUpdate(QStringRef newFilter) {
} }
_hashtagFilter = newFilter.toString(); _hashtagFilter = newFilter.toString();
if (cRecentSearchHashtags().isEmpty() && cRecentWriteHashtags().isEmpty()) { if (cRecentSearchHashtags().isEmpty() && cRecentWriteHashtags().isEmpty()) {
Local::readRecentHashtags(); Local::readRecentHashtagsAndBots();
} }
const RecentHashtagPack &recent(cRecentSearchHashtags()); const RecentHashtagPack &recent(cRecentSearchHashtags());
_hashtagResults.clear(); _hashtagResults.clear();
@ -1385,7 +1385,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (from < _filterResults.size()) { if (from < _filterResults.size()) {
int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width(); int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width();
if (to > _filterResults.size()) to = _filterResults.size(); if (to > _filterResults.size()) to = _filterResults.size();
for (; from < to; ++from) { for (; from < to; ++from) {
_filterResults[from]->history->peer->photo->load(); _filterResults[from]->history->peer->photo->load();
} }
@ -1434,7 +1434,7 @@ bool DialogsInner::choosePeer() {
} }
} }
cSetRecentSearchHashtags(recent); cSetRecentSearchHashtags(recent);
Local::writeRecentHashtags(); Local::writeRecentHashtagsAndBots();
emit refreshHashtags(); emit refreshHashtags();
selByMouse = true; selByMouse = true;
@ -1487,7 +1487,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
} }
} }
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) { if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
Local::readRecentHashtags(); Local::readRecentHashtagsAndBots();
recent = cRecentSearchHashtags(); recent = cRecentSearchHashtags();
} }
found = true; found = true;
@ -1495,7 +1495,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
} }
if (found) { if (found) {
cSetRecentSearchHashtags(recent); cSetRecentSearchHashtags(recent);
Local::writeRecentHashtags(); Local::writeRecentHashtagsAndBots();
} }
} }

View file

@ -3766,7 +3766,7 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
if (selected) { if (selected) {
p.fillRect(0, i * st::mentionHeight, width(), st::mentionHeight, st::mentionBgOver->b); p.fillRect(0, i * st::mentionHeight, width(), st::mentionHeight, st::mentionBgOver->b);
int skip = (st::mentionHeight - st::notifyClose.icon.pxHeight()) / 2; int skip = (st::mentionHeight - st::notifyClose.icon.pxHeight()) / 2;
if (!_hrows->isEmpty()) p.drawPixmap(QPoint(width() - st::notifyClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), App::sprite(), st::notifyClose.icon); if (!_hrows->isEmpty() || (!_mrows->isEmpty() && i < _recentInlineBotsInRows)) p.drawPixmap(QPoint(width() - st::notifyClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), App::sprite(), st::notifyClose.icon);
} }
p.setPen(st::black->p); p.setPen(st::black->p);
if (!_mrows->isEmpty()) { if (!_mrows->isEmpty()) {
@ -3902,6 +3902,10 @@ bool MentionsInner::select() {
return false; return false;
} }
void MentionsInner::setRecentInlineBotsInRows(int32 bots) {
_recentInlineBotsInRows = bots;
}
QString MentionsInner::getSelected() const { QString MentionsInner::getSelected() const {
int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size()); int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size());
if (_sel >= 0 && _sel < maxSel) { if (_sel >= 0 && _sel < maxSel) {
@ -3930,20 +3934,32 @@ void MentionsInner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true; _mouseSel = true;
onUpdateSelected(true); onUpdateSelected(true);
if (e->button() == Qt::LeftButton) { if (e->button() == Qt::LeftButton) {
if (_overDelete && _sel >= 0 && _sel < _hrows->size()) { if (_overDelete && _sel >= 0 && _sel < (_mrows->isEmpty() ? _hrows->size() : _recentInlineBotsInRows)) {
_mousePos = mapToGlobal(e->pos()); _mousePos = mapToGlobal(e->pos());
bool removed = false;
QString toRemove = _hrows->at(_sel); if (_mrows->isEmpty()) {
RecentHashtagPack recent(cRecentWriteHashtags()); QString toRemove = _hrows->at(_sel);
for (RecentHashtagPack::iterator i = recent.begin(); i != recent.cend();) { RecentHashtagPack &recent(cRefRecentWriteHashtags());
if (i->first == toRemove) { for (RecentHashtagPack::iterator i = recent.begin(); i != recent.cend();) {
i = recent.erase(i); if (i->first == toRemove) {
} else { i = recent.erase(i);
++i; removed = true;
} else {
++i;
}
}
} else {
UserData *toRemove = _mrows->at(_sel);
RecentInlineBots &recent(cRefRecentInlineBots());
int32 index = recent.indexOf(toRemove);
if (index >= 0) {
recent.remove(index);
removed = true;
} }
} }
cSetRecentWriteHashtags(recent); if (removed) {
Local::writeRecentHashtags(); Local::writeRecentHashtagsAndBots();
}
_parent->updateFiltered(); _parent->updateFiltered();
_mouseSel = true; _mouseSel = true;
@ -3980,8 +3996,8 @@ void MentionsInner::onUpdateSelected(bool force) {
if ((!force && !rect().contains(mouse)) || !_mouseSel) return; if ((!force && !rect().contains(mouse)) || !_mouseSel) return;
int w = width(), mouseY = mouse.y(); int w = width(), mouseY = mouse.y();
_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(); int32 sel = mouseY / int32(st::mentionHeight), maxSel = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size();
_overDelete = (!_hrows->isEmpty() || (!_mrows->isEmpty() && sel < _recentInlineBotsInRows)) ? (mouse.x() >= w - st::mentionHeight) : false;
if (sel < 0 || sel >= maxSel) { if (sel < 0 || sel >= maxSel) {
sel = -1; sel = -1;
} }
@ -4043,15 +4059,23 @@ void MentionsDropdown::paintEvent(QPaintEvent *e) {
} }
void MentionsDropdown::showFiltered(PeerData *peer, QString start) { void MentionsDropdown::showFiltered(PeerData *peer, QString query, bool start) {
if (query.isEmpty() || (peer->isUser() && query.at(0) == '@' && (!start || cRecentInlineBots().isEmpty()))) {
if (!isHidden()) {
hideStart();
}
return;
}
_chat = peer->asChat(); _chat = peer->asChat();
_user = peer->asUser(); _user = peer->asUser();
_channel = peer->asChannel(); _channel = peer->asChannel();
start = start.toLower(); query = query.toLower();
bool toDown = (_filter != start); bool toDown = (_filter != query);
if (toDown) { if (toDown) {
_filter = start; _filter = query;
} }
_addInlineBots = start;
updateFiltered(toDown); updateFiltered(toDown);
} }
@ -4063,13 +4087,34 @@ bool MentionsDropdown::clearFilteredBotCommands() {
} }
void MentionsDropdown::updateFiltered(bool toDown) { void MentionsDropdown::updateFiltered(bool toDown) {
int32 now = unixtime(); int32 now = unixtime(), recentInlineBots = 0;
MentionRows rows; MentionRows mrows;
HashtagRows hrows; HashtagRows hrows;
BotCommandRows brows; BotCommandRows brows;
if (_filter.at(0) == '@') {
if (_chat) {
mrows.reserve((_addInlineBots ? cRecentInlineBots().size() : 0) + (_chat->participants.isEmpty() ? _chat->lastAuthors.size() : _chat->participants.size()));
} else if (_channel && _channel->isMegagroup()) {
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
} else {
mrows.reserve((_addInlineBots ? cRecentInlineBots().size() : 0) + _channel->mgInfo->lastParticipants.size());
}
} else if (_addInlineBots) {
mrows.reserve(cRecentInlineBots().size());
}
if (_addInlineBots) {
for (RecentInlineBots::const_iterator i = cRecentInlineBots().cbegin(), e = cRecentInlineBots().cend(); i != e; ++i) {
UserData *user = *i;
if (user->username.isEmpty()) continue;
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
mrows.push_back(user);
++recentInlineBots;
}
}
}
if (_filter.at(0) == '@' && _chat) { if (_filter.at(0) == '@' && _chat) {
QMultiMap<int32, UserData*> ordered; QMultiMap<int32, UserData*> ordered;
rows.reserve(_chat->participants.isEmpty() ? _chat->lastAuthors.size() : _chat->participants.size()); mrows.reserve(mrows.size() + (_chat->participants.isEmpty() ? _chat->lastAuthors.size() : _chat->participants.size()));
if (_chat->noParticipantInfo()) { if (_chat->noParticipantInfo()) {
if (App::api()) App::api()->requestFullPeer(_chat); if (App::api()) App::api()->requestFullPeer(_chat);
} else if (!_chat->participants.isEmpty()) { } else if (!_chat->participants.isEmpty()) {
@ -4084,7 +4129,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
UserData *user = *i; UserData *user = *i;
if (user->username.isEmpty()) continue; if (user->username.isEmpty()) continue;
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue; if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
rows.push_back(user); mrows.push_back(user);
if (!ordered.isEmpty()) { if (!ordered.isEmpty()) {
ordered.remove(App::onlineForSort(user, now), user); ordered.remove(App::onlineForSort(user, now), user);
} }
@ -4092,7 +4137,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
if (!ordered.isEmpty()) { if (!ordered.isEmpty()) {
for (QMultiMap<int32, UserData*>::const_iterator i = ordered.cend(), b = ordered.cbegin(); i != b;) { for (QMultiMap<int32, UserData*>::const_iterator i = ordered.cend(), b = ordered.cbegin(); i != b;) {
--i; --i;
rows.push_back(i.value()); mrows.push_back(i.value());
} }
} }
} else if (_filter.at(0) == '@' && _channel && _channel->isMegagroup()) { } else if (_filter.at(0) == '@' && _channel && _channel->isMegagroup()) {
@ -4100,12 +4145,12 @@ void MentionsDropdown::updateFiltered(bool toDown) {
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) { if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
if (App::api()) App::api()->requestLastParticipants(_channel); if (App::api()) App::api()->requestLastParticipants(_channel);
} else { } else {
rows.reserve(_channel->mgInfo->lastParticipants.size()); mrows.reserve(mrows.size() + _channel->mgInfo->lastParticipants.size());
for (MegagroupInfo::LastParticipants::const_iterator i = _channel->mgInfo->lastParticipants.cbegin(), e = _channel->mgInfo->lastParticipants.cend(); i != e; ++i) { for (MegagroupInfo::LastParticipants::const_iterator i = _channel->mgInfo->lastParticipants.cbegin(), e = _channel->mgInfo->lastParticipants.cend(); i != e; ++i) {
UserData *user = *i; UserData *user = *i;
if (user->username.isEmpty()) continue; if (user->username.isEmpty()) continue;
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue; if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
rows.push_back(user); mrows.push_back(user);
} }
} }
} else if (_filter.at(0) == '#') { } else if (_filter.at(0) == '#') {
@ -4184,7 +4229,8 @@ void MentionsDropdown::updateFiltered(bool toDown) {
} }
} }
} }
rowsUpdated(rows, hrows, brows, toDown); rowsUpdated(mrows, hrows, brows, toDown);
_inner.setRecentInlineBotsInRows(recentInlineBots);
} }
void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown) { void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown) {

View file

@ -736,6 +736,8 @@ public:
bool moveSel(int direction); bool moveSel(int direction);
bool select(); bool select();
void setRecentInlineBotsInRows(int32 bots);
QString getSelected() const; QString getSelected() const;
signals: signals:
@ -756,6 +758,7 @@ private:
MentionRows *_mrows; MentionRows *_mrows;
HashtagRows *_hrows; HashtagRows *_hrows;
BotCommandRows *_brows; BotCommandRows *_brows;
int32 _recentInlineBotsInRows;
int32 _sel; int32 _sel;
bool _mouseSel; bool _mouseSel;
QPoint _mousePos; QPoint _mousePos;
@ -775,7 +778,7 @@ public:
void fastHide(); void fastHide();
bool clearFilteredBotCommands(); bool clearFilteredBotCommands();
void showFiltered(PeerData *peer, QString start); void showFiltered(PeerData *peer, QString query, bool start);
void updateFiltered(bool toDown = false); void updateFiltered(bool toDown = false);
void setBoundings(QRect boundings); void setBoundings(QRect boundings);
@ -820,7 +823,7 @@ private:
HashtagRows _hrows; HashtagRows _hrows;
BotCommandRows _brows; BotCommandRows _brows;
void rowsUpdated(const MentionRows &rows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown); void rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown);
ScrollArea _scroll; ScrollArea _scroll;
MentionsInner _inner; MentionsInner _inner;
@ -830,6 +833,7 @@ private:
ChannelData *_channel; ChannelData *_channel;
QString _filter; QString _filter;
QRect _boundings; QRect _boundings;
bool _addInlineBots;
int32 _width, _height; int32 _width, _height;
bool _hiding; bool _hiding;

View file

@ -129,7 +129,7 @@ namespace Ui {
void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) { void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) {
if (MainWidget *m = App::main()) { if (MainWidget *m = App::main()) {
QMetaObject::invokeMethod(m, SLOT(ui_showPeerHistoryAsync(quint64,qint32)), Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId)); QMetaObject::invokeMethod(m, "ui_showPeerHistoryAsync", Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId));
} }
} }

View file

@ -270,7 +270,9 @@ EmojiPtr FlatTextarea::getSingleEmoji() const {
return 0; return 0;
} }
void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&inlineBot, QString &inlineBotUsername) const { QString FlatTextarea::getMentionHashtagBotCommandPart(bool &start, UserData *&inlineBot, QString &inlineBotUsername) const {
start = false;
// check inline bot query // check inline bot query
const QString &text(getLastText()); const QString &text(getLastText());
int32 inlineUsernameStart = 1, inlineUsernameLength = 0, size = text.size(); int32 inlineUsernameStart = 1, inlineUsernameLength = 0, size = text.size();
@ -301,13 +303,12 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&i
inlineBot = InlineBotLookingUpData; inlineBot = InlineBotLookingUpData;
} }
} }
if (inlineBot == InlineBotLookingUpData) return; if (inlineBot == InlineBotLookingUpData) return QString();
if (inlineBot && (!inlineBot->botInfo || inlineBot->botInfo->inlinePlaceholder.isEmpty())) { if (inlineBot && (!inlineBot->botInfo || inlineBot->botInfo->inlinePlaceholder.isEmpty())) {
inlineBot = 0; inlineBot = 0;
} else { } else {
start = text.mid(inlineUsernameStart + inlineUsernameLength + 1); return text.mid(inlineUsernameStart + inlineUsernameLength + 1);
return;
} }
} else { } else {
inlineUsernameLength = 0; inlineUsernameLength = 0;
@ -319,7 +320,7 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&i
} }
int32 pos = textCursor().position(); int32 pos = textCursor().position();
if (textCursor().anchor() != pos) return; if (textCursor().anchor() != pos) return QString();
// check mention / hashtag / bot command // check mention / hashtag / bot command
QTextDocument *doc(document()); QTextDocument *doc(document());
@ -339,29 +340,33 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start, UserData *&i
for (int i = pos - p; i > 0; --i) { for (int i = pos - p; i > 0; --i) {
if (t.at(i - 1) == '@') { if (t.at(i - 1) == '@') {
if ((pos - p - i < 1 || t.at(i).isLetter()) && (i < 2 || !(t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_'))) { if ((pos - p - i < 1 || t.at(i).isLetter()) && (i < 2 || !(t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_'))) {
start = t.mid(i - 1, pos - p - i + 1); start = (i == 1) && (p == 0);
return t.mid(i - 1, pos - p - i + 1);
} else if ((pos - p - i < 1 || t.at(i).isLetter()) && i > 2 && (t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_') && !mentionInCommand) { } else if ((pos - p - i < 1 || t.at(i).isLetter()) && i > 2 && (t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_') && !mentionInCommand) {
mentionInCommand = true; mentionInCommand = true;
--i; --i;
continue; continue;
} }
return; return QString();
} else if (t.at(i - 1) == '#') { } else if (t.at(i - 1) == '#') {
if (i < 2 || !(t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_')) { if (i < 2 || !(t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_')) {
start = t.mid(i - 1, pos - p - i + 1); start = (i == 1) && (p == 0);
return t.mid(i - 1, pos - p - i + 1);
} }
return; return QString();
} else if (t.at(i - 1) == '/') { } else if (t.at(i - 1) == '/') {
if (i < 2) { if (i < 2) {
start = t.mid(i - 1, pos - p - i + 1); start = (i == 1) && (p == 0);
return t.mid(i - 1, pos - p - i + 1);
} }
return; return QString();
} }
if (pos - p - i > 127 || (!mentionInCommand && (pos - p - i > 63))) break; if (pos - p - i > 127 || (!mentionInCommand && (pos - p - i > 63))) break;
if (!t.at(i - 1).isLetterOrNumber() && t.at(i - 1) != '_') break; if (!t.at(i - 1).isLetterOrNumber() && t.at(i - 1) != '_') break;
} }
return; break;
} }
return QString();
} }
void FlatTextarea::onMentionHashtagOrBotCommandInsert(QString str) { void FlatTextarea::onMentionHashtagOrBotCommandInsert(QString str) {

View file

@ -64,7 +64,7 @@ public:
QSize minimumSizeHint() const; QSize minimumSizeHint() const;
EmojiPtr getSingleEmoji() const; EmojiPtr getSingleEmoji() const;
void getMentionHashtagBotCommandStart(QString &start, UserData *&contextBot, QString &contextBotUsername) const; QString getMentionHashtagBotCommandPart(bool &start, UserData *&contextBot, QString &contextBotUsername) const;
void removeSingleEmoji(); void removeSingleEmoji();
bool hasText() const; bool hasText() const;

View file

@ -5338,8 +5338,9 @@ void HistoryWidget::onCheckMentionDropdown() {
if (!_history || _a_show.animating()) return; if (!_history || _a_show.animating()) return;
UserData *bot = _inlineBot; UserData *bot = _inlineBot;
QString start, inlineBotUsername(_inlineBotUsername); bool start = false;
_field.getMentionHashtagBotCommandStart(start, _inlineBot, _inlineBotUsername); QString inlineBotUsername(_inlineBotUsername);
QString query = _field.getMentionHashtagBotCommandPart(start, _inlineBot, _inlineBotUsername);
if (inlineBotUsername != _inlineBotUsername) { if (inlineBotUsername != _inlineBotUsername) {
if (_inlineBotResolveRequestId) { if (_inlineBotResolveRequestId) {
Notify::inlineBotRequesting(false); Notify::inlineBotRequesting(false);
@ -5359,10 +5360,10 @@ void HistoryWidget::onCheckMentionDropdown() {
if (_inlineBot != bot) { if (_inlineBot != bot) {
updateFieldPlaceholder(); updateFieldPlaceholder();
} }
if (_inlineBot->username == (cTestMode() ? qstr("contextbot") : qstr("gif")) && start.isEmpty()) { if (_inlineBot->username == (cTestMode() ? qstr("contextbot") : qstr("gif")) && query.isEmpty()) {
_emojiPan.clearInlineBot(); _emojiPan.clearInlineBot();
} else { } else {
_emojiPan.queryInlineBot(_inlineBot, start); _emojiPan.queryInlineBot(_inlineBot, query);
} }
if (!_attachMention.isHidden()) { if (!_attachMention.isHidden()) {
_attachMention.hideStart(); _attachMention.hideStart();
@ -5373,16 +5374,12 @@ void HistoryWidget::onCheckMentionDropdown() {
_field.finishPlaceholder(); _field.finishPlaceholder();
} }
_emojiPan.clearInlineBot(); _emojiPan.clearInlineBot();
if (!start.isEmpty()) { if (!query.isEmpty()) {
if (start.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtags(); if (query.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtagsAndBots();
if (start.at(0) == '@' && _peer->isUser()) return; if (query.at(0) == '@' && cRecentInlineBots().isEmpty()) Local::readRecentHashtagsAndBots();
if (start.at(0) == '/' && _peer->isUser() && !_peer->asUser()->botInfo) return; if (query.at(0) == '/' && _peer->isUser() && !_peer->asUser()->botInfo) return;
_attachMention.showFiltered(_peer, start);
} else {
if (!_attachMention.isHidden()) {
_attachMention.hideStart();
}
} }
_attachMention.showFiltered(_peer, query, start);
} }
} }
@ -6428,6 +6425,18 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
_saveDraftStart = getms(); _saveDraftStart = getms();
onDraftSave(); onDraftSave();
RecentInlineBots &bots(cRefRecentInlineBots());
int32 index = bots.indexOf(bot);
if (index) {
if (index > 0) {
bots.removeAt(index);
} else if (bots.size() >= RecentInlineBotsLimit) {
bots.resize(RecentInlineBotsLimit - 1);
}
bots.push_front(bot);
Local::writeRecentHashtagsAndBots();
}
onCheckMentionDropdown(); onCheckMentionDropdown();
if (!_attachType.isHidden()) _attachType.hideStart(); if (!_attachType.isHidden()) _attachType.hideStart();

View file

@ -538,22 +538,22 @@ namespace {
FileKey _dataNameKey = 0; FileKey _dataNameKey = 0;
enum { // Local Storage Keys enum { // Local Storage Keys
lskUserMap = 0x00, lskUserMap = 0x00,
lskDraft = 0x01, // data: PeerId peer lskDraft = 0x01, // data: PeerId peer
lskDraftPosition = 0x02, // data: PeerId peer lskDraftPosition = 0x02, // data: PeerId peer
lskImages = 0x03, // data: StorageKey location lskImages = 0x03, // data: StorageKey location
lskLocations = 0x04, // no data lskLocations = 0x04, // no data
lskStickerImages = 0x05, // data: StorageKey location lskStickerImages = 0x05, // data: StorageKey location
lskAudios = 0x06, // data: StorageKey location lskAudios = 0x06, // data: StorageKey location
lskRecentStickersOld = 0x07, // no data lskRecentStickersOld = 0x07, // no data
lskBackground = 0x08, // no data lskBackground = 0x08, // no data
lskUserSettings = 0x09, // no data lskUserSettings = 0x09, // no data
lskRecentHashtags = 0x0a, // no data lskRecentHashtagsAndBots = 0x0a, // no data
lskStickers = 0x0b, // no data lskStickers = 0x0b, // no data
lskSavedPeers = 0x0c, // no data lskSavedPeers = 0x0c, // no data
lskReportSpamStatuses = 0x0d, // no data lskReportSpamStatuses = 0x0d, // no data
lskSavedGifsOld = 0x0e, lskSavedGifsOld = 0x0e, // no data
lskSavedGifs = 0x0f, lskSavedGifs = 0x0f, // no data
}; };
typedef QMap<PeerId, FileKey> DraftsMap; typedef QMap<PeerId, FileKey> DraftsMap;
@ -581,8 +581,8 @@ namespace {
bool _backgroundWasRead = false; bool _backgroundWasRead = false;
FileKey _userSettingsKey = 0; FileKey _userSettingsKey = 0;
FileKey _recentHashtagsKey = 0; FileKey _recentHashtagsAndBotsKey = 0;
bool _recentHashtagsWereRead = false; bool _recentHashtagsAndBotsWereRead = false;
FileKey _savedPeersKey = 0; FileKey _savedPeersKey = 0;
@ -726,18 +726,20 @@ namespace {
_fileLocationAliases.insert(MediaKey(kfirst, ksecond), MediaKey(vfirst, vsecond)); _fileLocationAliases.insert(MediaKey(kfirst, ksecond), MediaKey(vfirst, vsecond));
} }
_storageWebFilesSize = 0; if (!locations.stream.atEnd()) {
_webFilesMap.clear(); _storageWebFilesSize = 0;
_webFilesMap.clear();
quint32 webLocationsCount; quint32 webLocationsCount;
locations.stream >> webLocationsCount; locations.stream >> webLocationsCount;
for (quint32 i = 0; i < webLocationsCount; ++i) { for (quint32 i = 0; i < webLocationsCount; ++i) {
QString url; QString url;
quint64 key; quint64 key;
qint32 size; qint32 size;
locations.stream >> url >> key >> size; locations.stream >> url >> key >> size;
_webFilesMap.insert(url, FileDesc(key, size)); _webFilesMap.insert(url, FileDesc(key, size));
_storageWebFilesSize += size; _storageWebFilesSize += size;
}
} }
} }
} }
@ -1667,7 +1669,7 @@ namespace {
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
quint64 locationsKey = 0, reportSpamStatusesKey = 0; quint64 locationsKey = 0, reportSpamStatusesKey = 0;
quint64 recentStickersKeyOld = 0, stickersKey = 0, savedGifsKey = 0; quint64 recentStickersKeyOld = 0, stickersKey = 0, savedGifsKey = 0;
quint64 backgroundKey = 0, userSettingsKey = 0, recentHashtagsKey = 0, savedPeersKey = 0; quint64 backgroundKey = 0, userSettingsKey = 0, recentHashtagsAndBotsKey = 0, savedPeersKey = 0;
while (!map.stream.atEnd()) { while (!map.stream.atEnd()) {
quint32 keyType; quint32 keyType;
map.stream >> keyType; map.stream >> keyType;
@ -1744,8 +1746,8 @@ namespace {
case lskUserSettings: { case lskUserSettings: {
map.stream >> userSettingsKey; map.stream >> userSettingsKey;
} break; } break;
case lskRecentHashtags: { case lskRecentHashtagsAndBots: {
map.stream >> recentHashtagsKey; map.stream >> recentHashtagsAndBotsKey;
} break; } break;
case lskStickers: { case lskStickers: {
map.stream >> stickersKey; map.stream >> stickersKey;
@ -1788,7 +1790,7 @@ namespace {
_savedPeersKey = savedPeersKey; _savedPeersKey = savedPeersKey;
_backgroundKey = backgroundKey; _backgroundKey = backgroundKey;
_userSettingsKey = userSettingsKey; _userSettingsKey = userSettingsKey;
_recentHashtagsKey = recentHashtagsKey; _recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
_oldMapVersion = mapData.version; _oldMapVersion = mapData.version;
if (_oldMapVersion < AppVersion) { if (_oldMapVersion < AppVersion) {
_mapChanged = true; _mapChanged = true;
@ -1861,7 +1863,7 @@ namespace {
if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_recentHashtagsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_recentHashtagsAndBotsKey) mapSize += sizeof(quint32) + sizeof(quint64);
EncryptedDescriptor mapData(mapSize); EncryptedDescriptor mapData(mapSize);
if (!_draftsMap.isEmpty()) { if (!_draftsMap.isEmpty()) {
mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size()); mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size());
@ -1917,8 +1919,8 @@ namespace {
if (_userSettingsKey) { if (_userSettingsKey) {
mapData.stream << quint32(lskUserSettings) << quint64(_userSettingsKey); mapData.stream << quint32(lskUserSettings) << quint64(_userSettingsKey);
} }
if (_recentHashtagsKey) { if (_recentHashtagsAndBotsKey) {
mapData.stream << quint32(lskRecentHashtags) << quint64(_recentHashtagsKey); mapData.stream << quint32(lskRecentHashtagsAndBots) << quint64(_recentHashtagsAndBotsKey);
} }
map.writeEncrypted(mapData); map.writeEncrypted(mapData);
@ -2187,7 +2189,7 @@ namespace Local {
_storageWebFilesSize = 0; _storageWebFilesSize = 0;
_locationsKey = _reportSpamStatusesKey = 0; _locationsKey = _reportSpamStatusesKey = 0;
_recentStickersKeyOld = _stickersKey = _savedGifsKey = 0; _recentStickersKeyOld = _stickersKey = _savedGifsKey = 0;
_backgroundKey = _userSettingsKey = _recentHashtagsKey = _savedPeersKey = 0; _backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = 0;
_oldMapVersion = _oldSettingsVersion = 0; _oldMapVersion = _oldSettingsVersion = 0;
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapNow); _writeMap(WriteMapNow);
@ -3258,89 +3260,6 @@ namespace Local {
return false; return false;
} }
void writeRecentHashtags() {
if (!_working()) return;
const RecentHashtagPack &write(cRecentWriteHashtags()), &search(cRecentSearchHashtags());
if (write.isEmpty() && search.isEmpty()) readRecentHashtags();
if (write.isEmpty() && search.isEmpty()) {
if (_recentHashtagsKey) {
clearKey(_recentHashtagsKey);
_recentHashtagsKey = 0;
_mapChanged = true;
}
_writeMap();
} else {
if (!_recentHashtagsKey) {
_recentHashtagsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
}
quint32 size = sizeof(quint32) * 2, writeCnt = 0, searchCnt = 0;
for (RecentHashtagPack::const_iterator i = write.cbegin(); i != write.cend(); ++i) {
if (!i->first.isEmpty()) {
size += _stringSize(i->first) + sizeof(quint16);
++writeCnt;
}
}
for (RecentHashtagPack::const_iterator i = search.cbegin(); i != search.cend(); ++i) {
if (!i->first.isEmpty()) {
size += _stringSize(i->first) + sizeof(quint16);
++searchCnt;
}
}
EncryptedDescriptor data(size);
data.stream << quint32(writeCnt) << quint32(searchCnt);
for (RecentHashtagPack::const_iterator i = write.cbegin(); i != write.cend(); ++i) {
if (!i->first.isEmpty()) data.stream << i->first << quint16(i->second);
}
for (RecentHashtagPack::const_iterator i = search.cbegin(); i != search.cend(); ++i) {
if (!i->first.isEmpty()) data.stream << i->first << quint16(i->second);
}
FileWriteDescriptor file(_recentHashtagsKey);
file.writeEncrypted(data);
}
}
void readRecentHashtags() {
if (_recentHashtagsWereRead) return;
_recentHashtagsWereRead = true;
if (!_recentHashtagsKey) return;
FileReadDescriptor hashtags;
if (!readEncryptedFile(hashtags, _recentHashtagsKey)) {
clearKey(_recentHashtagsKey);
_recentHashtagsKey = 0;
_writeMap();
return;
}
quint32 writeCount = 0, searchCount = 0;
hashtags.stream >> writeCount >> searchCount;
QString tag;
quint16 count;
RecentHashtagPack write, search;
if (writeCount) {
write.reserve(writeCount);
for (uint32 i = 0; i < writeCount; ++i) {
hashtags.stream >> tag >> count;
write.push_back(qMakePair(tag.trimmed(), count));
}
}
if (searchCount) {
search.reserve(searchCount);
for (uint32 i = 0; i < searchCount; ++i) {
hashtags.stream >> tag >> count;
search.push_back(qMakePair(tag.trimmed(), count));
}
}
cSetRecentWriteHashtags(write);
cSetRecentSearchHashtags(search);
}
uint32 _peerSize(PeerData *peer) { uint32 _peerSize(PeerData *peer) {
uint32 result = sizeof(quint64) + sizeof(quint64) + _storageImageLocationSize(); uint32 result = sizeof(quint64) + sizeof(quint64) + _storageImageLocationSize();
if (peer->isUser()) { if (peer->isUser()) {
@ -3370,7 +3289,7 @@ namespace Local {
return result; return result;
} }
void _writePeer(QDataStream &stream, PeerData *peer) { void _writePeer(QDataStream &stream, PeerData *peer, int32 fileVersion = AppVersion) {
stream << quint64(peer->id) << quint64(peer->photoId); stream << quint64(peer->id) << quint64(peer->photoId);
_writeStorageImageLocation(stream, peer->photoLoc); _writeStorageImageLocation(stream, peer->photoLoc);
if (peer->isUser()) { if (peer->isUser()) {
@ -3380,6 +3299,9 @@ namespace Local {
if (AppVersion >= 9012) { if (AppVersion >= 9012) {
stream << qint32(user->flags); stream << qint32(user->flags);
} }
if (AppVersion >= 9016 || fileVersion >= 9016) {
stream << (user->botInfo ? user->botInfo->inlinePlaceholder : QString());
}
stream << qint32(user->onlineTill) << qint32(user->contact) << qint32(user->botInfo ? user->botInfo->version : -1); stream << qint32(user->onlineTill) << qint32(user->contact) << qint32(user->botInfo ? user->botInfo->version : -1);
} else if (peer->isChat()) { } else if (peer->isChat()) {
ChatData *chat = peer->asChat(); ChatData *chat = peer->asChat();
@ -3396,25 +3318,31 @@ namespace Local {
} }
} }
PeerData *_readPeer(FileReadDescriptor &from) { PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) {
PeerData *result = 0; PeerData *result = 0;
quint64 peerId = 0, photoId = 0; quint64 peerId = 0, photoId = 0;
from.stream >> peerId >> photoId; from.stream >> peerId >> photoId;
StorageImageLocation photoLoc(_readStorageImageLocation(from)); StorageImageLocation photoLoc(_readStorageImageLocation(from));
result = App::peerLoaded(peerId);
if (result && result->loaded) return result;
result = App::peer(peerId); result = App::peer(peerId);
result->loaded = true; result->loaded = true;
if (result->isUser()) { if (result->isUser()) {
UserData *user = result->asUser(); UserData *user = result->asUser();
QString first, last, phone, username; QString first, last, phone, username, inlinePlaceholder;
quint64 access; quint64 access;
qint32 flags = 0, onlineTill, contact, botInfoVersion; qint32 flags = 0, onlineTill, contact, botInfoVersion;
from.stream >> first >> last >> phone >> username >> access; from.stream >> first >> last >> phone >> username >> access;
if (from.version >= 9012) { if (from.version >= 9012) {
from.stream >> flags; from.stream >> flags;
} }
if (from.version >= 9016 || fileVersion >= 9016) {
from.stream >> inlinePlaceholder;
}
from.stream >> onlineTill >> contact >> botInfoVersion; from.stream >> onlineTill >> contact >> botInfoVersion;
bool showPhone = !isServiceUser(user->id) && (peerToUser(user->id) != MTP::authedId()) && (contact <= 0); bool showPhone = !isServiceUser(user->id) && (peerToUser(user->id) != MTP::authedId()) && (contact <= 0);
@ -3427,6 +3355,9 @@ namespace Local {
user->onlineTill = onlineTill; user->onlineTill = onlineTill;
user->contact = contact; user->contact = contact;
user->setBotInfoVersion(botInfoVersion); user->setBotInfoVersion(botInfoVersion);
if (!inlinePlaceholder.isEmpty() && user->botInfo) {
user->botInfo->inlinePlaceholder = inlinePlaceholder;
}
if (peerToUser(user->id) == MTP::authedId()) { if (peerToUser(user->id) == MTP::authedId()) {
user->input = MTP_inputPeerSelf(); user->input = MTP_inputPeerSelf();
@ -3489,6 +3420,113 @@ namespace Local {
return result; return result;
} }
void writeRecentHashtagsAndBots() {
if (!_working()) return;
const RecentHashtagPack &write(cRecentWriteHashtags()), &search(cRecentSearchHashtags());
const RecentInlineBots &bots(cRecentInlineBots());
if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) readRecentHashtagsAndBots();
if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) {
if (_recentHashtagsAndBotsKey) {
clearKey(_recentHashtagsAndBotsKey);
_recentHashtagsAndBotsKey = 0;
_mapChanged = true;
}
_writeMap();
} else {
if (!_recentHashtagsAndBotsKey) {
_recentHashtagsAndBotsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
}
quint32 size = sizeof(quint32) * 3, writeCnt = 0, searchCnt = 0, botsCnt = cRecentInlineBots().size();
for (RecentHashtagPack::const_iterator i = write.cbegin(), e = write.cend(); i != e; ++i) {
if (!i->first.isEmpty()) {
size += _stringSize(i->first) + sizeof(quint16);
++writeCnt;
}
}
for (RecentHashtagPack::const_iterator i = search.cbegin(), e = search.cend(); i != e; ++i) {
if (!i->first.isEmpty()) {
size += _stringSize(i->first) + sizeof(quint16);
++searchCnt;
}
}
for (RecentInlineBots::const_iterator i = bots.cbegin(), e = bots.cend(); i != e; ++i) {
size += _peerSize(*i);
}
EncryptedDescriptor data(size);
data.stream << quint32(writeCnt) << quint32(searchCnt);
for (RecentHashtagPack::const_iterator i = write.cbegin(), e = write.cend(); i != e; ++i) {
if (!i->first.isEmpty()) data.stream << i->first << quint16(i->second);
}
for (RecentHashtagPack::const_iterator i = search.cbegin(), e = search.cend(); i != e; ++i) {
if (!i->first.isEmpty()) data.stream << i->first << quint16(i->second);
}
data.stream << quint32(botsCnt);
for (RecentInlineBots::const_iterator i = bots.cbegin(), e = bots.cend(); i != e; ++i) {
_writePeer(data.stream, *i, 9016);
}
FileWriteDescriptor file(_recentHashtagsAndBotsKey);
file.writeEncrypted(data);
}
}
void readRecentHashtagsAndBots() {
if (_recentHashtagsAndBotsWereRead) return;
_recentHashtagsAndBotsWereRead = true;
if (!_recentHashtagsAndBotsKey) return;
FileReadDescriptor hashtags;
if (!readEncryptedFile(hashtags, _recentHashtagsAndBotsKey)) {
clearKey(_recentHashtagsAndBotsKey);
_recentHashtagsAndBotsKey = 0;
_writeMap();
return;
}
quint32 writeCount = 0, searchCount = 0, botsCount = 0;
hashtags.stream >> writeCount >> searchCount;
QString tag;
quint16 count;
RecentHashtagPack write, search;
RecentInlineBots bots;
if (writeCount) {
write.reserve(writeCount);
for (uint32 i = 0; i < writeCount; ++i) {
hashtags.stream >> tag >> count;
write.push_back(qMakePair(tag.trimmed(), count));
}
}
if (searchCount) {
search.reserve(searchCount);
for (uint32 i = 0; i < searchCount; ++i) {
hashtags.stream >> tag >> count;
search.push_back(qMakePair(tag.trimmed(), count));
}
}
cSetRecentWriteHashtags(write);
cSetRecentSearchHashtags(search);
if (!hashtags.stream.atEnd()) {
hashtags.stream >> botsCount;
if (botsCount) {
bots.reserve(botsCount);
for (uint32 i = 0; i < botsCount; ++i) {
PeerData *peer = _readPeer(hashtags, 9016);
if (peer && peer->isUser() && peer->asUser()->botInfo && !peer->asUser()->botInfo->inlinePlaceholder.isEmpty() && !peer->asUser()->username.isEmpty()) {
bots.push_back(peer->asUser());
}
}
}
cSetRecentInlineBots(bots);
}
}
void writeSavedPeers() { void writeSavedPeers() {
if (!_working()) return; if (!_working()) return;
@ -3651,8 +3689,8 @@ namespace Local {
_stickersKey = 0; _stickersKey = 0;
_mapChanged = true; _mapChanged = true;
} }
if (_recentHashtagsKey) { if (_recentHashtagsAndBotsKey) {
_recentHashtagsKey = 0; _recentHashtagsAndBotsKey = 0;
_mapChanged = true; _mapChanged = true;
} }
if (_savedPeersKey) { if (_savedPeersKey) {

View file

@ -157,8 +157,8 @@ namespace Local {
void writeBackground(int32 id, const QImage &img); void writeBackground(int32 id, const QImage &img);
bool readBackground(); bool readBackground();
void writeRecentHashtags(); void writeRecentHashtagsAndBots();
void readRecentHashtags(); void readRecentHashtagsAndBots();
void addSavedPeer(PeerData *peer, const QDateTime &position); void addSavedPeer(PeerData *peer, const QDateTime &position);
void removeSavedPeer(PeerData *peer); void removeSavedPeer(PeerData *peer);

View file

@ -1349,7 +1349,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
} }
} }
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) { if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
Local::readRecentHashtags(); Local::readRecentHashtagsAndBots();
recent = cRecentWriteHashtags(); recent = cRecentWriteHashtags();
} }
found = true; found = true;
@ -1357,7 +1357,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
} }
if (found) { if (found) {
cSetRecentWriteHashtags(recent); cSetRecentWriteHashtags(recent);
Local::writeRecentHashtags(); Local::writeRecentHashtagsAndBots();
} }
} }

View file

@ -121,6 +121,8 @@ int32 gSavedGifsLimit = 100;
RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags; RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags;
RecentInlineBots gRecentInlineBots;
bool gPasswordRecovered = false; bool gPasswordRecovered = false;
int32 gPasscodeBadTries = 0; int32 gPasscodeBadTries = 0;
uint64 gPasscodeLastTry = 0; uint64 gPasscodeLastTry = 0;

View file

@ -230,9 +230,13 @@ DeclareSetting(bool, ShowingSavedGifs);
DeclareSetting(int32, SavedGifsLimit); DeclareSetting(int32, SavedGifsLimit);
typedef QList<QPair<QString, ushort> > RecentHashtagPack; typedef QList<QPair<QString, ushort> > RecentHashtagPack;
DeclareSetting(RecentHashtagPack, RecentWriteHashtags); DeclareRefSetting(RecentHashtagPack, RecentWriteHashtags);
DeclareSetting(RecentHashtagPack, RecentSearchHashtags); DeclareSetting(RecentHashtagPack, RecentSearchHashtags);
class UserData;
typedef QVector<UserData*> RecentInlineBots;
DeclareRefSetting(RecentInlineBots, RecentInlineBots);
DeclareSetting(bool, PasswordRecovered); DeclareSetting(bool, PasswordRecovered);
DeclareSetting(int32, PasscodeBadTries); DeclareSetting(int32, PasscodeBadTries);

View file

@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,15,5 FILEVERSION 0,9,15,6
PRODUCTVERSION 0,9,15,5 PRODUCTVERSION 0,9,15,6
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.9.15.5" VALUE "FileVersion", "0.9.15.6"
VALUE "LegalCopyright", "Copyright (C) 2013" VALUE "LegalCopyright", "Copyright (C) 2013"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.15.5" VALUE "ProductVersion", "0.9.15.6"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"