This commit is contained in:
John Preston 2016-01-01 23:11:11 +08:00
commit 8116334557
28 changed files with 647 additions and 341 deletions

View File

@ -1307,6 +1307,13 @@ btnAttachEmoji: iconedButton(btnAttachDocument) {
width: 33px; width: 33px;
} }
emojiCircle: size(19px, 19px);
emojiCirclePeriod: 1500;
emojiCircleDuration: 500;
emojiCircleTop: 13px;
emojiCircleLine: 2px;
emojiCircleFg: #b9b9b9;
emojiCirclePart: 3.5;
btnBotKbShow: iconedButton(btnAttachEmoji) { btnBotKbShow: iconedButton(btnAttachEmoji) {
icon: sprite(375px, 74px, 21px, 21px); icon: sprite(375px, 74px, 21px, 21px);
iconPos: point(6px, 12px); iconPos: point(6px, 12px);

View File

@ -548,7 +548,7 @@ void Application::stopUpdate() {
void Application::startUpdateCheck(bool forceWait) { void Application::startUpdateCheck(bool forceWait) {
updateCheckTimer.stop(); updateCheckTimer.stop();
if (updateRequestId || updateThread || updateReply || !cAutoUpdate()) return; if (updateRequestId || updateThread || updateReply || !cAutoUpdate()) return;
int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart; int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(MTP::nonce<uint32>() % randDelay) - unixtime(); int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(MTP::nonce<uint32>() % randDelay) - unixtime();
bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay)); bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay));
@ -684,7 +684,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
socket.close(); socket.close();
psCheckLocalSocket(serverName); psCheckLocalSocket(serverName);
if (!server.listen(serverName)) { if (!server.listen(serverName)) {
DEBUG_LOG(("Application Error: failed to start listening to %1 server, error %2").arg(serverName).arg(int(server.serverError()))); DEBUG_LOG(("Application Error: failed to start listening to %1 server, error %2").arg(serverName).arg(int(server.serverError())));
return App::quit(); return App::quit();
@ -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();
} }
@ -769,7 +770,7 @@ void Application::startApp() {
} }
QNetworkProxyFactory::setUseSystemConfiguration(true); QNetworkProxyFactory::setUseSystemConfiguration(true);
if (state != Local::ReadMapPassNeeded) { if (state != Local::ReadMapPassNeeded) {
checkMapVersion(); checkMapVersion();
} }
@ -912,7 +913,7 @@ Application::~Application() {
cSetChatDogImage(0); cSetChatDogImage(0);
style::stopManager(); style::stopManager();
delete _translator; delete _translator;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 238 KiB

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

@ -1303,7 +1303,7 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
} }
void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) { void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) {
InlinePaintContext context(getms(), false, _previewShown, false); InlinePaintContext context(getms(), false, Ui::isLayerShown() || Ui::isMediaViewShown() || _previewShown, false);
int32 top = st::emojiPanHeader; int32 top = st::emojiPanHeader;
int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width()); int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width());
@ -3560,10 +3560,13 @@ void EmojiPan::inlineBotChanged() {
} }
_inlineCache.clear(); _inlineCache.clear();
s_inner.inlineBotChanged(); s_inner.inlineBotChanged();
Notify::inlineBotRequesting(false);
} }
void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) { void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
_inlineRequestId = 0; _inlineRequestId = 0;
Notify::inlineBotRequesting(false);
InlineCache::iterator it = _inlineCache.find(_inlineQuery); InlineCache::iterator it = _inlineCache.find(_inlineQuery);
@ -3659,6 +3662,8 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
bool EmojiPan::inlineResultsFail(const RPCError &error) { bool EmojiPan::inlineResultsFail(const RPCError &error) {
if (mtpIsFlood(error)) return false; if (mtpIsFlood(error)) return false;
Notify::inlineBotRequesting(false);
_inlineRequestId = 0; _inlineRequestId = 0;
return true; return true;
} }
@ -3674,6 +3679,7 @@ void EmojiPan::queryInlineBot(UserData *bot, QString query) {
if (_inlineRequestId) { if (_inlineRequestId) {
MTP::cancel(_inlineRequestId); MTP::cancel(_inlineRequestId);
_inlineRequestId = 0; _inlineRequestId = 0;
Notify::inlineBotRequesting(false);
} }
if (_inlineCache.contains(query)) { if (_inlineCache.contains(query)) {
_inlineRequestTimer.stop(); _inlineRequestTimer.stop();
@ -3696,6 +3702,7 @@ void EmojiPan::onInlineRequest() {
nextOffset = i.value()->nextOffset; nextOffset = i.value()->nextOffset;
if (nextOffset.isEmpty()) return; if (nextOffset.isEmpty()) return;
} }
Notify::inlineBotRequesting(true);
_inlineRequestId = MTP::send(MTPmessages_GetInlineBotResults(_inlineBot->inputUser, MTP_string(_inlineQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::inlineResultsDone), rpcFail(&EmojiPan::inlineResultsFail)); _inlineRequestId = MTP::send(MTPmessages_GetInlineBotResults(_inlineBot->inputUser, MTP_string(_inlineQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::inlineResultsDone), rpcFail(&EmojiPan::inlineResultsFail));
} }
@ -3759,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()) {
@ -3895,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) {
@ -3923,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;
@ -3973,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;
} }
@ -4036,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);
} }
@ -4056,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()) {
@ -4077,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);
} }
@ -4085,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()) {
@ -4093,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) == '#') {
@ -4177,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));
} }
} }
@ -149,6 +149,10 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user); if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user);
} }
void inlineBotRequesting(bool requesting) {
if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting);
}
void migrateUpdated(PeerData *peer) { void migrateUpdated(PeerData *peer) {
if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer);
} }

View File

@ -80,6 +80,8 @@ namespace Notify {
void userIsContactChanged(UserData *user, bool fromThisApp = false); void userIsContactChanged(UserData *user, bool fromThisApp = false);
void botCommandsChanged(UserData *user); void botCommandsChanged(UserData *user);
void inlineBotRequesting(bool requesting);
void migrateUpdated(PeerData *peer); void migrateUpdated(PeerData *peer);
void clipStopperHidden(ClipStopperType type); void clipStopperHidden(ClipStopperType type);

View File

@ -184,7 +184,7 @@ void AnimationManager::clipCallback(ClipReader *reader, qint32 threadIndex, qint
ClipReader::callback(reader, threadIndex, ClipReaderNotification(notification)); ClipReader::callback(reader, threadIndex, ClipReaderNotification(notification));
} }
QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, QImage &cache, bool hasAlpha) { QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, bool hasAlpha, QImage &cache) {
bool badSize = (original.width() != request.framew) || (original.height() != request.frameh); bool badSize = (original.width() != request.framew) || (original.height() != request.frameh);
bool needOuter = (request.outerw != request.framew) || (request.outerh != request.frameh); bool needOuter = (request.outerw != request.framew) || (request.outerh != request.frameh);
if (badSize || needOuter || hasAlpha || request.rounded) { if (badSize || needOuter || hasAlpha || request.rounded) {
@ -258,14 +258,16 @@ ClipReader::Frame *ClipReader::frameToShow() const { // 0 means not ready
return _frames + (((step + 1) / 2) % 3); return _frames + (((step + 1) / 2) % 3);
} }
ClipReader::Frame *ClipReader::frameToWrite() const { // 0 means not ready ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(); int32 step = _step.loadAcquire(), i = 0;
if (step == FirstFrameNotReadStep) { if (step == WaitingForRequestStep) {
return _frames; if (index) *index = 0;
} else if (step == WaitingForRequestStep) {
return 0; return 0;
} else if (step != FirstFrameNotReadStep) {
i = (((step + 3) / 2) % 3);
} }
return _frames + (((step + 3) / 2) % 3); if (index) *index = i;
return _frames + i;
} }
ClipReader::Frame *ClipReader::frameToRequestOther(bool check) const { ClipReader::Frame *ClipReader::frameToRequestOther(bool check) const {
@ -342,10 +344,10 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
frame->request.frameh = frameh * factor; frame->request.frameh = frameh * factor;
frame->request.outerw = outerw * factor; frame->request.outerw = outerw * factor;
frame->request.outerh = outerh * factor; frame->request.outerh = outerh * factor;
frame->pix = QPixmap();
QImage cache; QImage cacheForResize;
frame->pix = _prepareFrame(frame->request, frame->original, cache, true); frame->pix = QPixmap();
frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize);
Frame *other = frameToRequestOther(true); Frame *other = frameToRequestOther(true);
if (other) other->request = frame->request; if (other) other->request = frame->request;
@ -830,8 +832,7 @@ public:
, _location(_data.isEmpty() ? new FileLocation(location) : 0) , _location(_data.isEmpty() ? new FileLocation(location) : 0)
, _accessed(false) , _accessed(false)
, _implementation(0) , _implementation(0)
, _currentHasAlpha(true) , _frame(_frames)
, _nextHasAlpha(true)
, _width(0) , _width(0)
, _height(0) , _height(0)
, _previousMs(0) , _previousMs(0)
@ -850,12 +851,12 @@ public:
if (!_implementation && !init()) { if (!_implementation && !init()) {
return error(); return error();
} }
if (_currentOriginal.isNull()) { if (_frame->original.isNull()) {
if (!_implementation->readNextFrame(_currentOriginal, _currentHasAlpha, QSize())) { if (!_implementation->readNextFrame(_frame->original, _frame->alpha, QSize())) {
return error(); return error();
} }
_width = _currentOriginal.width(); _width = _frame->original.width();
_height = _currentOriginal.height(); _height = _frame->original.height();
return ClipProcessReinit; return ClipProcessReinit;
} }
return ClipProcessWait; return ClipProcessWait;
@ -868,12 +869,12 @@ public:
return start(ms); return start(ms);
} }
if (_current.isNull()) { // first frame read, but not yet prepared if (_frame->pix.isNull()) { // first frame read, but not yet prepared
_currentOriginal.setDevicePixelRatio(_request.factor); _frame->original.setDevicePixelRatio(_request.factor);
_previousMs = _currentMs; _previousMs = _currentMs;
_currentMs = ms; _currentMs = ms;
_current = _prepareFrame(_request, _currentOriginal, _currentCache, _currentHasAlpha); _frame->pix = _prepareFrame(_request, _frame->original, _frame->alpha, _frame->cache);
if (!prepareNextFrame()) { if (!prepareNextFrame()) {
return error(); return error();
@ -906,20 +907,16 @@ public:
void swapBuffers(uint64 ms = 0) { void swapBuffers(uint64 ms = 0) {
_previousMs = _currentMs; _previousMs = _currentMs;
_currentMs = qMax(ms, _nextUpdateMs); _currentMs = qMax(ms, _nextUpdateMs);
qSwap(_currentOriginal, _nextOriginal);
qSwap(_current, _next);
qSwap(_currentCache, _nextCache);
qSwap(_currentHasAlpha, _nextHasAlpha);
} }
bool prepareNextFrame() { bool prepareNextFrame() {
if (!_implementation->readNextFrame(_nextOriginal, _nextHasAlpha, QSize(_request.framew, _request.frameh))) { if (!_implementation->readNextFrame(_frame->original, _frame->alpha, QSize(_request.framew, _request.frameh))) {
return false; return false;
} }
_nextUpdateMs = _currentMs + nextFrameDelay(); _nextUpdateMs = _currentMs + nextFrameDelay();
_nextOriginal.setDevicePixelRatio(_request.factor); _frame->original.setDevicePixelRatio(_request.factor);
_next = QPixmap(); _frame->pix = QPixmap();
_next = _prepareFrame(_request, _nextOriginal, _nextCache, _nextHasAlpha); _frame->pix = _prepareFrame(_request, _frame->original, _frame->alpha, _frame->cache);
return true; return true;
} }
@ -979,9 +976,16 @@ private:
ClipReaderImplementation *_implementation; ClipReaderImplementation *_implementation;
ClipFrameRequest _request; ClipFrameRequest _request;
QPixmap _current, _next; struct Frame {
QImage _currentOriginal, _nextOriginal, _currentCache, _nextCache; Frame() : alpha(true) {
bool _currentHasAlpha, _nextHasAlpha; }
QPixmap pix;
QImage original, cache;
bool alpha;
};
Frame _frames[3];
Frame *_frame;
int32 _width, _height; int32 _width, _height;
uint64 _previousMs, _currentMs, _nextUpdateMs; uint64 _previousMs, _currentMs, _nextUpdateMs;
@ -1016,34 +1020,58 @@ void ClipReadManager::start(ClipReader *reader) {
} }
void ClipReadManager::update(ClipReader *reader) { void ClipReadManager::update(ClipReader *reader) {
QMutexLocker lock(&_readerPointersMutex); QReadLocker lock(&_readerPointersMutex);
_readerPointers.insert(reader, reader->_private); ReaderPointers::const_iterator i = _readerPointers.constFind(reader);
if (i == _readerPointers.cend()) {
lock.unlock();
QWriteLocker lock(&_readerPointersMutex);
_readerPointers.insert(reader, MutableAtomicInt(1));
} else {
i->v.storeRelease(1);
}
emit processDelayed(); emit processDelayed();
} }
void ClipReadManager::stop(ClipReader *reader) { void ClipReadManager::stop(ClipReader *reader) {
QMutexLocker lock(&_readerPointersMutex); if (!carries(reader)) return;
QWriteLocker lock(&_readerPointersMutex);
_readerPointers.remove(reader); _readerPointers.remove(reader);
emit processDelayed(); emit processDelayed();
} }
bool ClipReadManager::carries(ClipReader *reader) const { bool ClipReadManager::carries(ClipReader *reader) const {
QMutexLocker lock(&_readerPointersMutex); QReadLocker lock(&_readerPointersMutex);
return _readerPointers.contains(reader); return _readerPointers.contains(reader);
} }
bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) { ClipReadManager::ReaderPointers::iterator ClipReadManager::unsafeFindReaderPointer(ClipReaderPrivate *reader) {
QMutexLocker lock(&_readerPointersMutex);
ReaderPointers::iterator it = _readerPointers.find(reader->_interface); ReaderPointers::iterator it = _readerPointers.find(reader->_interface);
if (it != _readerPointers.cend() && it.key()->_private != reader) {
it = _readerPointers.end(); // it is a new reader which was realloced in the same address // could be a new reader which was realloced in the same address
} return (it == _readerPointers.cend() || it.key()->_private == reader) ? it : _readerPointers.end();
}
ClipReadManager::ReaderPointers::const_iterator ClipReadManager::constUnsafeFindReaderPointer(ClipReaderPrivate *reader) const {
ReaderPointers::const_iterator it = _readerPointers.constFind(reader->_interface);
// could be a new reader which was realloced in the same address
return (it == _readerPointers.cend() || it.key()->_private == reader) ? it : _readerPointers.cend();
}
bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
QReadLocker lock(&_readerPointersMutex);
ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader);
if (result == ClipProcessError) { if (result == ClipProcessError) {
if (it != _readerPointers.cend()) { if (it != _readerPointers.cend()) {
it.key()->error(); it.key()->error();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
_readerPointers.erase(it); lock.unlock();
QWriteLocker lock(&_readerPointersMutex);
ReaderPointers::iterator i = unsafeFindReaderPointer(reader);
if (i != _readerPointers.cend()) _readerPointers.erase(i);
} }
return false; return false;
} }
@ -1066,9 +1094,9 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
if (result == ClipProcessReinit || result == ClipProcessRepaint || result == ClipProcessStarted) { if (result == ClipProcessReinit || result == ClipProcessRepaint || result == ClipProcessStarted) {
ClipReader::Frame *frame = it.key()->frameToWrite(); ClipReader::Frame *frame = it.key()->frameToWrite();
t_assert(frame != 0); t_assert(frame != 0);
frame->pix = QPixmap(); frame->clear();
frame->pix = reader->_current; frame->pix = reader->_frame->pix;
frame->original = reader->_currentOriginal; frame->original = reader->_frame->original;
frame->displayed = false; frame->displayed = false;
it.key()->moveToNextWrite(); it.key()->moveToNextWrite();
if (result == ClipProcessReinit) { if (result == ClipProcessReinit) {
@ -1082,7 +1110,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) { ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
if (!handleProcessResult(reader, result, ms)) { if (!handleProcessResult(reader, result, ms)) {
_loadLevel.fetchAndAddRelaxed(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_width * reader->_height)); _loadLevel.fetchAndAddRelaxed(-1 * (reader->_frame->original.isNull() ? AverageGifSize : reader->_width * reader->_height));
delete reader; delete reader;
return ResultHandleRemove; return ResultHandleRemove;
} }
@ -1110,27 +1138,37 @@ void ClipReadManager::process() {
uint64 ms = getms(), minms = ms + 86400 * 1000ULL; uint64 ms = getms(), minms = ms + 86400 * 1000ULL;
{ {
QMutexLocker lock(&_readerPointersMutex); QReadLocker lock(&_readerPointersMutex);
for (ReaderPointers::iterator i = _readerPointers.begin(), e = _readerPointers.end(); i != e; ++i) { for (ReaderPointers::iterator it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) {
if (i.value()) { if (it->v.loadAcquire()) {
Readers::iterator it = _readers.find(i.value()); Readers::iterator i = _readers.find(it.key()->_private);
if (it == _readers.cend()) { if (i == _readers.cend()) {
_readers.insert(i.value(), 0); _readers.insert(it.key()->_private, 0);
} else { } else {
it.value() = ms; i.value() = ms;
if (it.key()->_paused && !i.key()->_paused.loadAcquire()) { if (i.key()->_paused && !it.key()->_paused.loadAcquire()) {
it.key()->_paused = false; i.key()->_paused = false;
} }
} }
ClipReader::Frame *frame = i.key()->frameToWrite(); ClipReader::Frame *frame = it.key()->frameToWrite();
if (frame) i.value()->_request = frame->request; if (frame) it.key()->_private->_request = frame->request;
i.value() = 0; it->v.storeRelease(0);
} }
} }
} }
for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e;) { for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e;) {
if (i.value() <= ms) { if (i.value() <= ms) {
{
QReadLocker lock(&_readerPointersMutex);
ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(i.key());
if (it != _readerPointers.cend()) {
int32 index = 0;
ClipReader::Frame *frame = it.key()->frameToWrite(&index);
if (frame) frame->clear();
i.key()->_frame = i.key()->_frames + index;
}
}
ClipProcessResult result = i.key()->process(ms); ClipProcessResult result = i.key()->process(ms);
ResultHandleState state = handleResult(i.key(), result, ms); ResultHandleState state = handleResult(i.key(), result, ms);
@ -1167,13 +1205,13 @@ void ClipReadManager::finish() {
} }
void ClipReadManager::clear() { void ClipReadManager::clear() {
QMutexLocker lock(&_readerPointersMutex); {
for (ReaderPointers::iterator i = _readerPointers.begin(), e = _readerPointers.end(); i != e; ++i) { QWriteLocker lock(&_readerPointersMutex);
if (i.value()) { for (ReaderPointers::iterator it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) {
i.key()->_private = 0; it.key()->_private = 0;
} }
} _readerPointers.clear();
_readerPointers.clear(); }
for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e; ++i) { for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e; ++i) {
delete i.key(); delete i.key();
@ -1195,12 +1233,12 @@ MTPDocumentAttribute clipReadAnimatedAttributes(const QString &fname, const QByt
if (reader->readNextFrame(cover, hasAlpha, QSize())) { if (reader->readNextFrame(cover, hasAlpha, QSize())) {
if (cover.width() > 0 && cover.height() > 0 && cover.width() < cover.height() * 10 && cover.height() < cover.width() * 10) { if (cover.width() > 0 && cover.height() > 0 && cover.width() < cover.height() * 10 && cover.height() < cover.width() * 10) {
if (hasAlpha) { if (hasAlpha) {
QImage cache; QImage cacheForResize;
ClipFrameRequest request; ClipFrameRequest request;
request.framew = request.outerw = cover.width(); request.framew = request.outerw = cover.width();
request.frameh = request.outerh = cover.height(); request.frameh = request.outerh = cover.height();
request.factor = 1; request.factor = 1;
cover = _prepareFrame(request, cover, cache, hasAlpha).toImage(); cover = _prepareFrame(request, cover, hasAlpha, cacheForResize).toImage();
} }
int32 duration = reader->duration(); int32 duration = reader->duration();
delete reader; delete reader;

View File

@ -563,6 +563,10 @@ private:
struct Frame { struct Frame {
Frame() : displayed(false), when(0) { Frame() : displayed(false), when(0) {
} }
void clear() {
pix = QPixmap();
original = QImage();
}
QPixmap pix; QPixmap pix;
QImage original; QImage original;
ClipFrameRequest request; ClipFrameRequest request;
@ -571,7 +575,7 @@ private:
}; };
mutable Frame _frames[3]; mutable Frame _frames[3];
Frame *frameToShow() const; // 0 means not ready Frame *frameToShow() const; // 0 means not ready
Frame *frameToWrite() const; // 0 means not ready Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
Frame *frameToRequestOther(bool check) const; Frame *frameToRequestOther(bool check) const;
void moveToNextShow() const; void moveToNextShow() const;
void moveToNextWrite() const; void moveToNextWrite() const;
@ -629,9 +633,17 @@ private:
void clear(); void clear();
QAtomicInt _loadLevel; QAtomicInt _loadLevel;
typedef QMap<ClipReader*, ClipReaderPrivate*> ReaderPointers; struct MutableAtomicInt {
MutableAtomicInt(int value) : v(value) {
}
mutable QAtomicInt v;
};
typedef QMap<ClipReader*, MutableAtomicInt> ReaderPointers;
ReaderPointers _readerPointers; ReaderPointers _readerPointers;
mutable QMutex _readerPointersMutex; mutable QReadWriteLock _readerPointersMutex;
ReaderPointers::const_iterator constUnsafeFindReaderPointer(ClipReaderPrivate *reader) const;
ReaderPointers::iterator unsafeFindReaderPointer(ClipReaderPrivate *reader);
bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms); bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);

View File

@ -289,6 +289,59 @@ void MaskedButton::paintEvent(QPaintEvent *e) {
} }
} }
EmojiButton::EmojiButton(QWidget *parent, const style::iconedButton &st) : IconedButton(parent, st)
, _loading(false)
, _a_loading(animation(this, &EmojiButton::step_loading)) {
}
void EmojiButton::paintEvent(QPaintEvent *e) {
QPainter p(this);
uint64 ms = getms();
float64 loading = a_loading.current(ms, _loading ? 1 : 0);
p.setOpacity(_opacity * (1 - loading));
p.fillRect(e->rect(), a_bg.current());
p.setOpacity(a_opacity.current() * _opacity * (1 - loading));
const QRect &i((_state & StateDown) ? _st.downIcon : _st.icon);
if (i.width()) {
const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos);
p.drawPixmap(t, App::sprite(), i);
}
QRect inner(QPoint((width() - st::emojiCircle.width()) / 2, st::emojiCircleTop), st::emojiCircle);
int32 full = 5760;
int32 start = qRound(full * float64(ms % uint64(st::emojiCirclePeriod)) / st::emojiCirclePeriod), part = qRound(full / st::emojiCirclePart);
p.setBrush(Qt::NoBrush);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.setPen(QPen(st::emojiCircleFg->c, st::emojiCircleLine));
p.setOpacity(a_opacity.current() * _opacity);
p.drawEllipse(inner);
p.setPen(QPen(st::white->c, st::emojiCircleLine));
p.setOpacity(loading);
p.drawArc(inner, (full - start) % full, part);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
}
void EmojiButton::setLoading(bool loading) {
if (_loading != loading) {
EnsureAnimation(a_loading, _loading ? 1. : 0., func(this, &EmojiButton::update));
a_loading.start(loading ? 1. : 0., st::emojiCircleDuration);
_loading = loading;
if (_loading) {
_a_loading.start();
} else {
_a_loading.stop();
}
}
}
BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent) BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent)
, _text(text.toUpper()) , _text(text.toUpper())
, _fullText(text.toUpper()) , _fullText(text.toUpper())

View File

@ -106,7 +106,7 @@ public:
void setText(const QString &text); void setText(const QString &text);
QString getText() const; QString getText() const;
public slots: public slots:
void onStateChange(int oldState, ButtonStateChangeSource source); void onStateChange(int oldState, ButtonStateChangeSource source);
@ -136,6 +136,28 @@ public:
}; };
class EmojiButton : public IconedButton {
Q_OBJECT
public:
EmojiButton(QWidget *parent, const style::iconedButton &st);
void paintEvent(QPaintEvent *e);
void setLoading(bool loading);
private:
bool _loading;
FloatAnimation a_loading;
Animation _a_loading;
void step_loading(uint64 ms, bool timer) {
if (timer) {
update();
}
}
};
class BoxButton : public Button { class BoxButton : public Button {
Q_OBJECT Q_OBJECT

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

@ -3028,6 +3028,10 @@ void HistoryWidget::notify_botCommandsChanged(UserData *user) {
} }
} }
void HistoryWidget::notify_inlineBotRequesting(bool requesting) {
_attachEmoji.setLoading(requesting);
}
void HistoryWidget::notify_userIsBotChanged(UserData *user) { void HistoryWidget::notify_userIsBotChanged(UserData *user) {
if (_peer && _peer == user) { if (_peer && _peer == user) {
_list->notifyIsBotChanged(); _list->notifyIsBotChanged();
@ -4971,6 +4975,7 @@ bool HistoryWidget::hasBroadcastToggle() const {
} }
void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) { void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) {
Notify::inlineBotRequesting(false);
_inlineBotUsername = QString(); _inlineBotUsername = QString();
if (result.type() == mtpc_contacts_resolvedPeer) { if (result.type() == mtpc_contacts_resolvedPeer) {
const MTPDcontacts_resolvedPeer &d(result.c_contacts_resolvedPeer()); const MTPDcontacts_resolvedPeer &d(result.c_contacts_resolvedPeer());
@ -4982,6 +4987,8 @@ void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result)
bool HistoryWidget::inlineBotResolveFail(QString name, const RPCError &error) { bool HistoryWidget::inlineBotResolveFail(QString name, const RPCError &error) {
if (mtpIsFlood(error)) return false; if (mtpIsFlood(error)) return false;
Notify::inlineBotRequesting(false);
if (name == _inlineBotUsername) { if (name == _inlineBotUsername) {
_inlineBot = 0; _inlineBot = 0;
onCheckMentionDropdown(); onCheckMentionDropdown();
@ -5331,14 +5338,17 @@ 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);
MTP::cancel(_inlineBotResolveRequestId); MTP::cancel(_inlineBotResolveRequestId);
_inlineBotResolveRequestId = 0; _inlineBotResolveRequestId = 0;
} }
if (_inlineBot == InlineBotLookingUpData) { if (_inlineBot == InlineBotLookingUpData) {
Notify::inlineBotRequesting(true);
_inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername)); _inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername));
return; return;
} }
@ -5350,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();
@ -5364,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);
} }
} }
@ -6419,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

@ -568,6 +568,7 @@ public:
void notify_historyItemLayoutChanged(const HistoryItem *item); void notify_historyItemLayoutChanged(const HistoryItem *item);
void notify_automaticLoadSettingsChangedGif(); void notify_automaticLoadSettingsChangedGif();
void notify_botCommandsChanged(UserData *user); void notify_botCommandsChanged(UserData *user);
void notify_inlineBotRequesting(bool requesting);
void notify_userIsBotChanged(UserData *user); void notify_userIsBotChanged(UserData *user);
void notify_migrateUpdated(PeerData *peer); void notify_migrateUpdated(PeerData *peer);
void notify_clipStopperHidden(ClipStopperType type); void notify_clipStopperHidden(ClipStopperType type);
@ -784,7 +785,9 @@ private:
FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute; FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute;
mtpRequestId _unblockRequest, _reportSpamRequest; mtpRequestId _unblockRequest, _reportSpamRequest;
IconedButton _attachDocument, _attachPhoto, _attachEmoji, _kbShow, _kbHide, _cmdStart; IconedButton _attachDocument, _attachPhoto;
EmojiButton _attachEmoji;
IconedButton _kbShow, _kbHide, _cmdStart;
FlatCheckbox _broadcast; FlatCheckbox _broadcast;
bool _cmdStartShown; bool _cmdStartShown;
MessageField _field; MessageField _field;

View File

@ -1529,13 +1529,14 @@ LayoutInlineGif::~LayoutInlineGif() {
} }
void LayoutInlineGif::prepareThumb(int32 width, int32 height, const QSize &frame) const { void LayoutInlineGif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (_doc && !_doc->thumb->isNull()) { DocumentData *doc = _doc ? _doc : (_result ? _result->doc : 0);
if (_doc->thumb->loaded()) { if (doc && !doc->thumb->isNull()) {
if (doc->thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = _doc->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); _thumb = doc->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height);
} }
} else { } else {
_doc->thumb->load(); doc->thumb->load();
} }
} else if (_result && !_result->thumb_url.isEmpty()) { } else if (_result && !_result->thumb_url.isEmpty()) {
if (_result->thumb->loaded()) { if (_result->thumb->loaded()) {
@ -1746,19 +1747,20 @@ QSize LayoutInlinePhoto::countFrameSize() const {
} }
void LayoutInlinePhoto::prepareThumb(int32 width, int32 height, const QSize &frame) const { void LayoutInlinePhoto::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (_photo) { PhotoData *photo = _photo ? _photo : (_result ? _result->photo : 0);
if (_photo->medium->loaded()) { if (photo) {
if (photo->medium->loaded()) {
if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { 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); _thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height);
} }
_thumbLoaded = true; _thumbLoaded = true;
} else { } else {
if (_photo->thumb->loaded()) { if (photo->thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = _photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); _thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height);
} }
} }
_photo->medium->load(); photo->medium->load();
} }
} else { } else {
if (_result->thumb->loaded()) { if (_result->thumb->loaded()) {

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,47 +3318,60 @@ 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::peer(peerId); result = App::peerLoaded(peerId);
result->loaded = true; bool wasLoaded = (result && result->loaded);
if (!wasLoaded) {
result = App::peer(peerId);
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);
QString pname = (showPhone && !phone.isEmpty()) ? App::formatPhone(phone) : QString(); QString pname = (showPhone && !phone.isEmpty()) ? App::formatPhone(phone) : QString();
user->setName(first, last, pname, username); if (!wasLoaded) {
user->setName(first, last, pname, username);
user->access = access; user->access = access;
user->flags = flags; user->flags = flags;
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();
user->inputUser = MTP_inputUserSelf(); user->inputUser = MTP_inputUserSelf();
} else { } else {
user->input = MTP_inputPeerUser(MTP_int(peerToUser(user->id)), MTP_long((user->access == UserNoAccess) ? 0 : user->access)); user->input = MTP_inputPeerUser(MTP_int(peerToUser(user->id)), MTP_long((user->access == UserNoAccess) ? 0 : user->access));
user->inputUser = MTP_inputUser(MTP_int(peerToUser(user->id)), MTP_long((user->access == UserNoAccess) ? 0 : user->access)); user->inputUser = MTP_inputUser(MTP_int(peerToUser(user->id)), MTP_long((user->access == UserNoAccess) ? 0 : user->access));
}
user->photo = photoLoc.isNull() ? ImagePtr(userDefPhoto(user->colorIndex)) : ImagePtr(photoLoc);
} }
user->photo = photoLoc.isNull() ? ImagePtr(userDefPhoto(user->colorIndex)) : ImagePtr(photoLoc);
} else if (result->isChat()) { } else if (result->isChat()) {
ChatData *chat = result->asChat(); ChatData *chat = result->asChat();
@ -3450,19 +3385,21 @@ namespace Local {
// flagsData was haveLeft // flagsData was haveLeft
flags = (flagsData == 1 ? MTPDchat::flag_left : 0); flags = (flagsData == 1 ? MTPDchat::flag_left : 0);
} }
chat->updateName(name, QString(), QString()); if (!wasLoaded) {
chat->count = count; chat->updateName(name, QString(), QString());
chat->date = date; chat->count = count;
chat->version = version; chat->date = date;
chat->creator = creator; chat->version = version;
chat->isForbidden = (forbidden == 1); chat->creator = creator;
chat->flags = flags; chat->isForbidden = (forbidden == 1);
chat->invitationUrl = invitationUrl; chat->flags = flags;
chat->invitationUrl = invitationUrl;
chat->input = MTP_inputPeerChat(MTP_int(peerToChat(chat->id))); chat->input = MTP_inputPeerChat(MTP_int(peerToChat(chat->id)));
chat->inputChat = MTP_int(peerToChat(chat->id)); chat->inputChat = MTP_int(peerToChat(chat->id));
chat->photo = photoLoc.isNull() ? ImagePtr(chatDefPhoto(chat->colorIndex)) : ImagePtr(photoLoc); chat->photo = photoLoc.isNull() ? ImagePtr(chatDefPhoto(chat->colorIndex)) : ImagePtr(photoLoc);
}
} else if (result->isChannel()) { } else if (result->isChannel()) {
ChannelData *channel = result->asChannel(); ChannelData *channel = result->asChannel();
@ -3471,24 +3408,135 @@ namespace Local {
qint32 date, version, adminned, forbidden, flags; qint32 date, version, adminned, forbidden, flags;
from.stream >> name >> access >> date >> version >> forbidden >> flags >> invitationUrl; from.stream >> name >> access >> date >> version >> forbidden >> flags >> invitationUrl;
channel->updateName(name, QString(), QString()); if (!wasLoaded) {
channel->access = access; channel->updateName(name, QString(), QString());
channel->date = date; channel->access = access;
channel->version = version; channel->date = date;
channel->isForbidden = (forbidden == 1); channel->version = version;
channel->flags = flags; channel->isForbidden = (forbidden == 1);
channel->invitationUrl = invitationUrl; channel->flags = flags;
channel->invitationUrl = invitationUrl;
channel->input = MTP_inputPeerChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); channel->input = MTP_inputPeerChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access));
channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access));
channel->photo = photoLoc.isNull() ? ImagePtr((channel->isMegagroup() ? chatDefPhoto(channel->colorIndex) : channelDefPhoto(channel->colorIndex))) : ImagePtr(photoLoc); channel->photo = photoLoc.isNull() ? ImagePtr((channel->isMegagroup() ? chatDefPhoto(channel->colorIndex) : channelDefPhoto(channel->colorIndex))) : ImagePtr(photoLoc);
}
}
if (!wasLoaded) {
App::markPeerUpdated(result);
emit App::main()->peerPhotoChanged(result);
} }
App::markPeerUpdated(result);
emit App::main()->peerPhotoChanged(result);
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;
@ -3594,6 +3642,7 @@ namespace Local {
struct ClearManagerData { struct ClearManagerData {
QThread *thread; QThread *thread;
StorageMap images, stickers, audios; StorageMap images, stickers, audios;
WebFilesMap webFiles;
QMutex mutex; QMutex mutex;
QList<int> tasks; QList<int> tasks;
bool working; bool working;
@ -3650,8 +3699,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) {
@ -3693,6 +3742,22 @@ namespace Local {
_storageStickersSize = 0; _storageStickersSize = 0;
_mapChanged = true; _mapChanged = true;
} }
if (data->webFiles.isEmpty()) {
data->webFiles = _webFilesMap;
} else {
for (WebFilesMap::const_iterator i = _webFilesMap.cbegin(), e = _webFilesMap.cend(); i != e; ++i) {
QString k = i.key();
while (data->webFiles.constFind(k) != data->webFiles.cend()) {
k += '#';
}
data->webFiles.insert(k, i.value());
}
}
if (!_webFilesMap.isEmpty()) {
_webFilesMap.clear();
_storageWebFilesSize = 0;
_writeLocations();
}
if (data->audios.isEmpty()) { if (data->audios.isEmpty()) {
data->audios = _audiosMap; data->audios = _audiosMap;
} else { } else {
@ -3745,6 +3810,7 @@ namespace Local {
int task = 0; int task = 0;
bool result = false; bool result = false;
StorageMap images, stickers, audios; StorageMap images, stickers, audios;
WebFilesMap webFiles;
{ {
QMutexLocker lock(&data->mutex); QMutexLocker lock(&data->mutex);
if (data->tasks.isEmpty()) { if (data->tasks.isEmpty()) {
@ -3755,6 +3821,7 @@ namespace Local {
images = data->images; images = data->images;
stickers = data->stickers; stickers = data->stickers;
audios = data->audios; audios = data->audios;
webFiles = data->webFiles;
} }
switch (task) { switch (task) {
case ClearManagerAll: { case ClearManagerAll: {
@ -3786,6 +3853,9 @@ namespace Local {
for (StorageMap::const_iterator i = audios.cbegin(), e = audios.cend(); i != e; ++i) { for (StorageMap::const_iterator i = audios.cbegin(), e = audios.cend(); i != e; ++i) {
clearKey(i.value().first, UserPath); clearKey(i.value().first, UserPath);
} }
for (WebFilesMap::const_iterator i = webFiles.cbegin(), e = webFiles.cend(); i != e; ++i) {
clearKey(i.value().first, UserPath);
}
result = true; result = true;
break; break;
} }

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

@ -759,6 +759,10 @@ void MainWidget::notify_botCommandsChanged(UserData *bot) {
history.notify_botCommandsChanged(bot); history.notify_botCommandsChanged(bot);
} }
void MainWidget::notify_inlineBotRequesting(bool requesting) {
history.notify_inlineBotRequesting(requesting);
}
void MainWidget::notify_userIsBotChanged(UserData *bot) { void MainWidget::notify_userIsBotChanged(UserData *bot) {
history.notify_userIsBotChanged(bot); history.notify_userIsBotChanged(bot);
} }
@ -1345,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;
@ -1353,7 +1357,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
} }
if (found) { if (found) {
cSetRecentWriteHashtags(recent); cSetRecentWriteHashtags(recent);
Local::writeRecentHashtags(); Local::writeRecentHashtagsAndBots();
} }
} }

View File

@ -416,6 +416,7 @@ public:
void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back); void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back);
void notify_botCommandsChanged(UserData *bot); void notify_botCommandsChanged(UserData *bot);
void notify_inlineBotRequesting(bool requesting);
void notify_userIsBotChanged(UserData *bot); void notify_userIsBotChanged(UserData *bot);
void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_userIsContactChanged(UserData *user, bool fromThisApp);
void notify_migrateUpdated(PeerData *peer); void notify_migrateUpdated(PeerData *peer);

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

@ -462,7 +462,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
top += st::setHeaderSkip; top += st::setHeaderSkip;
#ifndef TDESKTOP_DISABLE_AUTOUPDATE #ifndef TDESKTOP_DISABLE_AUTOUPDATE
top += _autoUpdate.height(); top += _autoUpdate.height();
QString textToDraw; QString textToDraw;
if (cAutoUpdate()) { if (cAutoUpdate()) {
switch (_updatingState) { switch (_updatingState) {
@ -485,7 +485,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
if (cPlatform() == dbipWindows) { if (cPlatform() == dbipWindows) {
top += _workmodeTray.height() + st::setLittleSkip; top += _workmodeTray.height() + st::setLittleSkip;
top += _workmodeWindow.height() + st::setSectionSkip; top += _workmodeWindow.height() + st::setSectionSkip;
top += _autoStart.height() + st::setLittleSkip; top += _autoStart.height() + st::setLittleSkip;
top += _startMinimized.height() + st::setSectionSkip; top += _startMinimized.height() + st::setSectionSkip;
@ -500,12 +500,12 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_scale_label)); p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_scale_label));
top += st::setHeaderSkip; top += st::setHeaderSkip;
top += _dpiAutoScale.height() + st::setLittleSkip; top += _dpiAutoScale.height() + st::setLittleSkip;
top += _dpiSlider.height() + st::dpiFont4->height; top += _dpiSlider.height() + st::dpiFont4->height;
int32 sLeft = _dpiSlider.x() + _dpiWidth1 / 2, sWidth = _dpiSlider.width(); int32 sLeft = _dpiSlider.x() + _dpiWidth1 / 2, sWidth = _dpiSlider.width();
float64 sStep = (sWidth - _dpiWidth1 / 2 - _dpiWidth4 / 2) / float64(dbisScaleCount - 2); float64 sStep = (sWidth - _dpiWidth1 / 2 - _dpiWidth4 / 2) / float64(dbisScaleCount - 2);
p.setFont(st::dpiFont1->f); p.setFont(st::dpiFont1->f);
p.setPen((scaleIs(dbisOne) ? st::dpiActive : st::dpiInactive)->p); p.setPen((scaleIs(dbisOne) ? st::dpiActive : st::dpiInactive)->p);
p.drawText(sLeft + qRound(0 * sStep) - _dpiWidth1 / 2, top - (st::dpiFont4->height - st::dpiFont1->height) / 2 - st::dpiFont1->descent, scaleLabel(dbisOne)); p.drawText(sLeft + qRound(0 * sStep) - _dpiWidth1 / 2, top - (st::dpiFont4->height - st::dpiFont1->height) / 2 - st::dpiFont1->descent, scaleLabel(dbisOne));
p.setFont(st::dpiFont2->f); p.setFont(st::dpiFont2->f);
@ -519,7 +519,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
p.drawText(sLeft + qRound(3 * sStep) - _dpiWidth4 / 2, top - (st::dpiFont4->height - st::dpiFont4->height) / 2 - st::dpiFont4->descent, scaleLabel(dbisTwo)); p.drawText(sLeft + qRound(3 * sStep) - _dpiWidth4 / 2, top - (st::dpiFont4->height - st::dpiFont4->height) / 2 - st::dpiFont4->descent, scaleLabel(dbisTwo));
p.setFont(st::linkFont->f); p.setFont(st::linkFont->f);
} }
if (self()) { if (self()) {
// chat options // chat options
p.setFont(st::setHeaderFont->f); p.setFont(st::setHeaderFont->f);
@ -575,7 +575,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
top += st::setHeaderSkip; top += st::setHeaderSkip;
int32 cntImages = Local::hasImages() + Local::hasStickers(), cntAudios = Local::hasAudios(); int32 cntImages = Local::hasImages() + Local::hasStickers() + Local::hasWebFiles(), cntAudios = Local::hasAudios();
if (cntImages > 0 && cntAudios > 0) { if (cntImages > 0 && cntAudios > 0) {
if (_localStorageHeight != 2) { if (_localStorageHeight != 2) {
cntAudios = 0; cntAudios = 0;
@ -587,7 +587,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
} }
} }
if (cntImages > 0) { if (cntImages > 0) {
QString cnt = lng_settings_images_cached(lt_count, cntImages, lt_size, formatSizeText(Local::storageImagesSize() + Local::storageStickersSize())); QString cnt = lng_settings_images_cached(lt_count, cntImages, lt_size, formatSizeText(Local::storageImagesSize() + Local::storageStickersSize() + Local::storageWebFilesSize()));
p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, cnt); p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, cnt);
} }
if (_localStorageHeight == 2) top += _localStorageClear.height() + st::setLittleSkip; if (_localStorageHeight == 2) top += _localStorageClear.height() + st::setLittleSkip;
@ -644,7 +644,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
p.setPen(st::setHeaderColor->p); p.setPen(st::setHeaderColor->p);
p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_advanced)); p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_advanced));
top += st::setHeaderSkip; top += st::setHeaderSkip;
p.setFont(st::linkFont->f); p.setFont(st::linkFont->f);
p.setPen(st::black->p); p.setPen(st::black->p);
if (self()) { if (self()) {
@ -702,7 +702,7 @@ void SettingsInner::resizeEvent(QResizeEvent *e) {
if (cPlatform() == dbipWindows) { if (cPlatform() == dbipWindows) {
_workmodeTray.move(_left, top); top += _workmodeTray.height() + st::setLittleSkip; _workmodeTray.move(_left, top); top += _workmodeTray.height() + st::setLittleSkip;
_workmodeWindow.move(_left, top); top += _workmodeWindow.height() + st::setSectionSkip; _workmodeWindow.move(_left, top); top += _workmodeWindow.height() + st::setSectionSkip;
_autoStart.move(_left, top); top += _autoStart.height() + st::setLittleSkip; _autoStart.move(_left, top); top += _autoStart.height() + st::setLittleSkip;
_startMinimized.move(_left, top); top += _startMinimized.height() + st::setSectionSkip; _startMinimized.move(_left, top); top += _startMinimized.height() + st::setSectionSkip;
@ -715,7 +715,7 @@ void SettingsInner::resizeEvent(QResizeEvent *e) {
_dpiAutoScale.move(_left, top); top += _dpiAutoScale.height() + st::setLittleSkip; _dpiAutoScale.move(_left, top); top += _dpiAutoScale.height() + st::setLittleSkip;
_dpiSlider.move(_left, top); top += _dpiSlider.height() + st::dpiFont4->height; _dpiSlider.move(_left, top); top += _dpiSlider.height() + st::dpiFont4->height;
} }
// chat options // chat options
if (self()) { if (self()) {
top += st::setHeaderSkip; top += st::setHeaderSkip;
@ -739,7 +739,7 @@ void SettingsInner::resizeEvent(QResizeEvent *e) {
// local storage // local storage
_localStorageClear.move(_left + st::setWidth - _localStorageClear.width(), top + st::setHeaderTop + st::setHeaderFont->ascent - st::linkFont->ascent); _localStorageClear.move(_left + st::setWidth - _localStorageClear.width(), top + st::setHeaderTop + st::setHeaderFont->ascent - st::linkFont->ascent);
top += st::setHeaderSkip; top += st::setHeaderSkip;
if ((Local::hasImages() || Local::hasStickers()) && Local::hasAudios()) { if ((Local::hasImages() || Local::hasStickers() || Local::hasWebFiles()) && Local::hasAudios()) {
_localStorageHeight = 2; _localStorageHeight = 2;
top += _localStorageClear.height() + st::setLittleSkip; top += _localStorageClear.height() + st::setLittleSkip;
} else { } else {
@ -1031,7 +1031,7 @@ void SettingsInner::showAll() {
_workmodeTray.hide(); _workmodeTray.hide();
} }
_workmodeWindow.hide(); _workmodeWindow.hide();
_autoStart.hide(); _autoStart.hide();
_startMinimized.hide(); _startMinimized.hide();
@ -1163,7 +1163,7 @@ void SettingsInner::onUpdatePhotoCancel() {
void SettingsInner::onUpdatePhoto() { void SettingsInner::onUpdatePhoto() {
saveError(); saveError();
QStringList imgExtensions(cImgExtensions()); QStringList imgExtensions(cImgExtensions());
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)"));
QImage img; QImage img;

View File

@ -453,9 +453,9 @@ void Window::firstShow() {
trayIconMenu = new QMenu(this); trayIconMenu = new QMenu(this);
trayIconMenu->setFont(QFont("Tahoma")); trayIconMenu->setFont(QFont("Tahoma"));
#endif #endif
QString notificationItem = lang(cDesktopNotify() QString notificationItem = lang(cDesktopNotify()
? lng_disable_notifications_from_tray : lng_enable_notifications_from_tray); ? lng_disable_notifications_from_tray : lng_enable_notifications_from_tray);
if (cPlatform() == dbipWindows || cPlatform() == dbipMac || cPlatform() == dbipMacOld) { if (cPlatform() == dbipWindows || cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()))->setEnabled(true); trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()))->setEnabled(true);
trayIconMenu->addAction(notificationItem, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true); trayIconMenu->addAction(notificationItem, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true);
@ -940,7 +940,7 @@ void Window::paintEvent(QPaintEvent *e) {
HitTestType Window::hitTest(const QPoint &p) const { HitTestType Window::hitTest(const QPoint &p) const {
int x(p.x()), y(p.y()), w(width()), h(height()); int x(p.x()), y(p.y()), w(width()), h(height());
const int32 raw = psResizeRowWidth(); const int32 raw = psResizeRowWidth();
if (!windowState().testFlag(Qt::WindowMaximized)) { if (!windowState().testFlag(Qt::WindowMaximized)) {
if (y < raw) { if (y < raw) {
@ -1019,7 +1019,7 @@ void Window::mouseMoveEvent(QMouseEvent *e) {
if (dragging) { if (dragging) {
if (windowState().testFlag(Qt::WindowMaximized)) { if (windowState().testFlag(Qt::WindowMaximized)) {
setWindowState(windowState() & ~Qt::WindowMaximized); setWindowState(windowState() & ~Qt::WindowMaximized);
dragStart = e->globalPos() - frameGeometry().topLeft(); dragStart = e->globalPos() - frameGeometry().topLeft();
} else { } else {
move(e->globalPos() - dragStart); move(e->globalPos() - dragStart);
@ -1260,7 +1260,7 @@ Window::TempDirState Window::localStorageState() {
if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) { if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) {
return TempDirRemoving; return TempDirRemoving;
} }
return (Local::hasImages() || Local::hasStickers() || Local::hasAudios()) ? TempDirExists : TempDirEmpty; return (Local::hasImages() || Local::hasStickers() || Local::hasWebFiles() || Local::hasAudios()) ? TempDirExists : TempDirEmpty;
} }
void Window::tempDirDelete(int task) { void Window::tempDirDelete(int task) {

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"

View File

@ -3,4 +3,4 @@ AppVersionStrMajor 0.9
AppVersionStrSmall 0.9.15 AppVersionStrSmall 0.9.15
AppVersionStr 0.9.15 AppVersionStr 0.9.15
DevChannel 0 DevChannel 0
BetaVersion 9015005 BetaVersion 9015006