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;
}
emojiCircle: size(19px, 19px);
emojiCirclePeriod: 1500;
emojiCircleDuration: 500;
emojiCircleTop: 13px;
emojiCircleLine: 2px;
emojiCircleFg: #b9b9b9;
emojiCirclePart: 3.5;
btnBotKbShow: iconedButton(btnAttachEmoji) {
icon: sprite(375px, 74px, 21px, 21px);
iconPos: point(6px, 12px);

View File

@ -548,7 +548,7 @@ void Application::stopUpdate() {
void Application::startUpdateCheck(bool forceWait) {
updateCheckTimer.stop();
if (updateRequestId || updateThread || updateReply || !cAutoUpdate()) return;
int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(MTP::nonce<uint32>() % randDelay) - unixtime();
bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay));
@ -684,7 +684,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
socket.close();
psCheckLocalSocket(serverName);
if (!server.listen(serverName)) {
DEBUG_LOG(("Application Error: failed to start listening to %1 server, error %2").arg(serverName).arg(int(server.serverError())));
return App::quit();
@ -705,10 +705,11 @@ void Application::checkMapVersion() {
if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion()) {
QString versionFeatures;
if (cDevVersion() && Local::oldMapVersion() < 9014) {
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));
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 = 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) {
// 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 {
versionFeatures = lang(lng_new_version_minor).trimmed();
}
@ -769,7 +770,7 @@ void Application::startApp() {
}
QNetworkProxyFactory::setUseSystemConfiguration(true);
if (state != Local::ReadMapPassNeeded) {
checkMapVersion();
}
@ -912,7 +913,7 @@ Application::~Application() {
cSetChatDogImage(0);
style::stopManager();
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 wchar_t *AppVersionStr = L"0.9.15";
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 *AppName = L"Telegram Desktop";
@ -87,6 +87,7 @@ enum {
AverageGifSize = 320 * 240,
WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it
InlineBotRequestDelay = 400, // wait 400ms before context bot realtime request
RecentInlineBotsLimit = 10,
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();
MsgId actId = App::main()->activeMsgId();
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);
_filterResults[from]->paint(p, w, active, selected, paintingOther);
p.translate(0, st::dlgHeight);
@ -872,7 +872,7 @@ void DialogsInner::onHashtagFilterUpdate(QStringRef newFilter) {
}
_hashtagFilter = newFilter.toString();
if (cRecentSearchHashtags().isEmpty() && cRecentWriteHashtags().isEmpty()) {
Local::readRecentHashtags();
Local::readRecentHashtagsAndBots();
}
const RecentHashtagPack &recent(cRecentSearchHashtags());
_hashtagResults.clear();
@ -1385,7 +1385,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (from < _filterResults.size()) {
int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width();
if (to > _filterResults.size()) to = _filterResults.size();
for (; from < to; ++from) {
_filterResults[from]->history->peer->photo->load();
}
@ -1434,7 +1434,7 @@ bool DialogsInner::choosePeer() {
}
}
cSetRecentSearchHashtags(recent);
Local::writeRecentHashtags();
Local::writeRecentHashtagsAndBots();
emit refreshHashtags();
selByMouse = true;
@ -1487,7 +1487,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
}
}
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
Local::readRecentHashtags();
Local::readRecentHashtagsAndBots();
recent = cRecentSearchHashtags();
}
found = true;
@ -1495,7 +1495,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
}
if (found) {
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) {
InlinePaintContext context(getms(), false, _previewShown, false);
InlinePaintContext context(getms(), false, Ui::isLayerShown() || Ui::isMediaViewShown() || _previewShown, false);
int32 top = st::emojiPanHeader;
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();
s_inner.inlineBotChanged();
Notify::inlineBotRequesting(false);
}
void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
_inlineRequestId = 0;
Notify::inlineBotRequesting(false);
InlineCache::iterator it = _inlineCache.find(_inlineQuery);
@ -3659,6 +3662,8 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
bool EmojiPan::inlineResultsFail(const RPCError &error) {
if (mtpIsFlood(error)) return false;
Notify::inlineBotRequesting(false);
_inlineRequestId = 0;
return true;
}
@ -3674,6 +3679,7 @@ void EmojiPan::queryInlineBot(UserData *bot, QString query) {
if (_inlineRequestId) {
MTP::cancel(_inlineRequestId);
_inlineRequestId = 0;
Notify::inlineBotRequesting(false);
}
if (_inlineCache.contains(query)) {
_inlineRequestTimer.stop();
@ -3696,6 +3702,7 @@ void EmojiPan::onInlineRequest() {
nextOffset = i.value()->nextOffset;
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));
}
@ -3759,7 +3766,7 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
if (selected) {
p.fillRect(0, i * st::mentionHeight, width(), st::mentionHeight, st::mentionBgOver->b);
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);
if (!_mrows->isEmpty()) {
@ -3895,6 +3902,10 @@ bool MentionsInner::select() {
return false;
}
void MentionsInner::setRecentInlineBotsInRows(int32 bots) {
_recentInlineBotsInRows = bots;
}
QString MentionsInner::getSelected() const {
int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size());
if (_sel >= 0 && _sel < maxSel) {
@ -3923,20 +3934,32 @@ void MentionsInner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true;
onUpdateSelected(true);
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());
QString toRemove = _hrows->at(_sel);
RecentHashtagPack recent(cRecentWriteHashtags());
for (RecentHashtagPack::iterator i = recent.begin(); i != recent.cend();) {
if (i->first == toRemove) {
i = recent.erase(i);
} else {
++i;
bool removed = false;
if (_mrows->isEmpty()) {
QString toRemove = _hrows->at(_sel);
RecentHashtagPack &recent(cRefRecentWriteHashtags());
for (RecentHashtagPack::iterator i = recent.begin(); i != recent.cend();) {
if (i->first == toRemove) {
i = recent.erase(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);
Local::writeRecentHashtags();
if (removed) {
Local::writeRecentHashtagsAndBots();
}
_parent->updateFiltered();
_mouseSel = true;
@ -3973,8 +3996,8 @@ void MentionsInner::onUpdateSelected(bool force) {
if ((!force && !rect().contains(mouse)) || !_mouseSel) return;
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();
_overDelete = (!_hrows->isEmpty() || (!_mrows->isEmpty() && sel < _recentInlineBotsInRows)) ? (mouse.x() >= w - st::mentionHeight) : false;
if (sel < 0 || sel >= maxSel) {
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();
_user = peer->asUser();
_channel = peer->asChannel();
start = start.toLower();
bool toDown = (_filter != start);
query = query.toLower();
bool toDown = (_filter != query);
if (toDown) {
_filter = start;
_filter = query;
}
_addInlineBots = start;
updateFiltered(toDown);
}
@ -4056,13 +4087,34 @@ bool MentionsDropdown::clearFilteredBotCommands() {
}
void MentionsDropdown::updateFiltered(bool toDown) {
int32 now = unixtime();
MentionRows rows;
int32 now = unixtime(), recentInlineBots = 0;
MentionRows mrows;
HashtagRows hrows;
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) {
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 (App::api()) App::api()->requestFullPeer(_chat);
} else if (!_chat->participants.isEmpty()) {
@ -4077,7 +4129,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
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;
rows.push_back(user);
mrows.push_back(user);
if (!ordered.isEmpty()) {
ordered.remove(App::onlineForSort(user, now), user);
}
@ -4085,7 +4137,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
if (!ordered.isEmpty()) {
for (QMultiMap<int32, UserData*>::const_iterator i = ordered.cend(), b = ordered.cbegin(); i != b;) {
--i;
rows.push_back(i.value());
mrows.push_back(i.value());
}
}
} 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 (App::api()) App::api()->requestLastParticipants(_channel);
} 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) {
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;
rows.push_back(user);
mrows.push_back(user);
}
}
} 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) {

View File

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

View File

@ -129,7 +129,7 @@ namespace Ui {
void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) {
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);
}
void inlineBotRequesting(bool requesting) {
if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting);
}
void migrateUpdated(PeerData *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 botCommandsChanged(UserData *user);
void inlineBotRequesting(bool requesting);
void migrateUpdated(PeerData *peer);
void clipStopperHidden(ClipStopperType type);

View File

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

View File

@ -563,6 +563,10 @@ private:
struct Frame {
Frame() : displayed(false), when(0) {
}
void clear() {
pix = QPixmap();
original = QImage();
}
QPixmap pix;
QImage original;
ClipFrameRequest request;
@ -571,7 +575,7 @@ private:
};
mutable Frame _frames[3];
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;
void moveToNextShow() const;
void moveToNextWrite() const;
@ -629,9 +633,17 @@ private:
void clear();
QAtomicInt _loadLevel;
typedef QMap<ClipReader*, ClipReaderPrivate*> ReaderPointers;
struct MutableAtomicInt {
MutableAtomicInt(int value) : v(value) {
}
mutable QAtomicInt v;
};
typedef QMap<ClipReader*, MutableAtomicInt> 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);

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)
, _text(text.toUpper())
, _fullText(text.toUpper())

View File

@ -106,7 +106,7 @@ public:
void setText(const QString &text);
QString getText() const;
public slots:
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 {
Q_OBJECT

View File

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

View File

@ -64,7 +64,7 @@ public:
QSize minimumSizeHint() const;
EmojiPtr getSingleEmoji() const;
void getMentionHashtagBotCommandStart(QString &start, UserData *&contextBot, QString &contextBotUsername) const;
QString getMentionHashtagBotCommandPart(bool &start, UserData *&contextBot, QString &contextBotUsername) const;
void removeSingleEmoji();
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) {
if (_peer && _peer == user) {
_list->notifyIsBotChanged();
@ -4971,6 +4975,7 @@ bool HistoryWidget::hasBroadcastToggle() const {
}
void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) {
Notify::inlineBotRequesting(false);
_inlineBotUsername = QString();
if (result.type() == mtpc_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) {
if (mtpIsFlood(error)) return false;
Notify::inlineBotRequesting(false);
if (name == _inlineBotUsername) {
_inlineBot = 0;
onCheckMentionDropdown();
@ -5331,14 +5338,17 @@ void HistoryWidget::onCheckMentionDropdown() {
if (!_history || _a_show.animating()) return;
UserData *bot = _inlineBot;
QString start, inlineBotUsername(_inlineBotUsername);
_field.getMentionHashtagBotCommandStart(start, _inlineBot, _inlineBotUsername);
bool start = false;
QString inlineBotUsername(_inlineBotUsername);
QString query = _field.getMentionHashtagBotCommandPart(start, _inlineBot, _inlineBotUsername);
if (inlineBotUsername != _inlineBotUsername) {
if (_inlineBotResolveRequestId) {
Notify::inlineBotRequesting(false);
MTP::cancel(_inlineBotResolveRequestId);
_inlineBotResolveRequestId = 0;
}
if (_inlineBot == InlineBotLookingUpData) {
Notify::inlineBotRequesting(true);
_inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername));
return;
}
@ -5350,10 +5360,10 @@ void HistoryWidget::onCheckMentionDropdown() {
if (_inlineBot != bot) {
updateFieldPlaceholder();
}
if (_inlineBot->username == (cTestMode() ? qstr("contextbot") : qstr("gif")) && start.isEmpty()) {
if (_inlineBot->username == (cTestMode() ? qstr("contextbot") : qstr("gif")) && query.isEmpty()) {
_emojiPan.clearInlineBot();
} else {
_emojiPan.queryInlineBot(_inlineBot, start);
_emojiPan.queryInlineBot(_inlineBot, query);
}
if (!_attachMention.isHidden()) {
_attachMention.hideStart();
@ -5364,16 +5374,12 @@ void HistoryWidget::onCheckMentionDropdown() {
_field.finishPlaceholder();
}
_emojiPan.clearInlineBot();
if (!start.isEmpty()) {
if (start.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtags();
if (start.at(0) == '@' && _peer->isUser()) return;
if (start.at(0) == '/' && _peer->isUser() && !_peer->asUser()->botInfo) return;
_attachMention.showFiltered(_peer, start);
} else {
if (!_attachMention.isHidden()) {
_attachMention.hideStart();
}
if (!query.isEmpty()) {
if (query.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtagsAndBots();
if (query.at(0) == '@' && cRecentInlineBots().isEmpty()) Local::readRecentHashtagsAndBots();
if (query.at(0) == '/' && _peer->isUser() && !_peer->asUser()->botInfo) return;
}
_attachMention.showFiltered(_peer, query, start);
}
}
@ -6419,6 +6425,18 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
_saveDraftStart = getms();
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();
if (!_attachType.isHidden()) _attachType.hideStart();

View File

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

View File

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

View File

@ -538,22 +538,22 @@ namespace {
FileKey _dataNameKey = 0;
enum { // Local Storage Keys
lskUserMap = 0x00,
lskDraft = 0x01, // data: PeerId peer
lskDraftPosition = 0x02, // data: PeerId peer
lskImages = 0x03, // data: StorageKey location
lskLocations = 0x04, // no data
lskStickerImages = 0x05, // data: StorageKey location
lskAudios = 0x06, // data: StorageKey location
lskRecentStickersOld = 0x07, // no data
lskBackground = 0x08, // no data
lskUserSettings = 0x09, // no data
lskRecentHashtags = 0x0a, // no data
lskStickers = 0x0b, // no data
lskSavedPeers = 0x0c, // no data
lskReportSpamStatuses = 0x0d, // no data
lskSavedGifsOld = 0x0e,
lskSavedGifs = 0x0f,
lskUserMap = 0x00,
lskDraft = 0x01, // data: PeerId peer
lskDraftPosition = 0x02, // data: PeerId peer
lskImages = 0x03, // data: StorageKey location
lskLocations = 0x04, // no data
lskStickerImages = 0x05, // data: StorageKey location
lskAudios = 0x06, // data: StorageKey location
lskRecentStickersOld = 0x07, // no data
lskBackground = 0x08, // no data
lskUserSettings = 0x09, // no data
lskRecentHashtagsAndBots = 0x0a, // no data
lskStickers = 0x0b, // no data
lskSavedPeers = 0x0c, // no data
lskReportSpamStatuses = 0x0d, // no data
lskSavedGifsOld = 0x0e, // no data
lskSavedGifs = 0x0f, // no data
};
typedef QMap<PeerId, FileKey> DraftsMap;
@ -581,8 +581,8 @@ namespace {
bool _backgroundWasRead = false;
FileKey _userSettingsKey = 0;
FileKey _recentHashtagsKey = 0;
bool _recentHashtagsWereRead = false;
FileKey _recentHashtagsAndBotsKey = 0;
bool _recentHashtagsAndBotsWereRead = false;
FileKey _savedPeersKey = 0;
@ -726,18 +726,20 @@ namespace {
_fileLocationAliases.insert(MediaKey(kfirst, ksecond), MediaKey(vfirst, vsecond));
}
_storageWebFilesSize = 0;
_webFilesMap.clear();
if (!locations.stream.atEnd()) {
_storageWebFilesSize = 0;
_webFilesMap.clear();
quint32 webLocationsCount;
locations.stream >> webLocationsCount;
for (quint32 i = 0; i < webLocationsCount; ++i) {
QString url;
quint64 key;
qint32 size;
locations.stream >> url >> key >> size;
_webFilesMap.insert(url, FileDesc(key, size));
_storageWebFilesSize += size;
quint32 webLocationsCount;
locations.stream >> webLocationsCount;
for (quint32 i = 0; i < webLocationsCount; ++i) {
QString url;
quint64 key;
qint32 size;
locations.stream >> url >> key >> size;
_webFilesMap.insert(url, FileDesc(key, size));
_storageWebFilesSize += size;
}
}
}
}
@ -1667,7 +1669,7 @@ namespace {
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
quint64 locationsKey = 0, reportSpamStatusesKey = 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()) {
quint32 keyType;
map.stream >> keyType;
@ -1744,8 +1746,8 @@ namespace {
case lskUserSettings: {
map.stream >> userSettingsKey;
} break;
case lskRecentHashtags: {
map.stream >> recentHashtagsKey;
case lskRecentHashtagsAndBots: {
map.stream >> recentHashtagsAndBotsKey;
} break;
case lskStickers: {
map.stream >> stickersKey;
@ -1788,7 +1790,7 @@ namespace {
_savedPeersKey = savedPeersKey;
_backgroundKey = backgroundKey;
_userSettingsKey = userSettingsKey;
_recentHashtagsKey = recentHashtagsKey;
_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
_oldMapVersion = mapData.version;
if (_oldMapVersion < AppVersion) {
_mapChanged = true;
@ -1861,7 +1863,7 @@ namespace {
if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_backgroundKey) 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);
if (!_draftsMap.isEmpty()) {
mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size());
@ -1917,8 +1919,8 @@ namespace {
if (_userSettingsKey) {
mapData.stream << quint32(lskUserSettings) << quint64(_userSettingsKey);
}
if (_recentHashtagsKey) {
mapData.stream << quint32(lskRecentHashtags) << quint64(_recentHashtagsKey);
if (_recentHashtagsAndBotsKey) {
mapData.stream << quint32(lskRecentHashtagsAndBots) << quint64(_recentHashtagsAndBotsKey);
}
map.writeEncrypted(mapData);
@ -2187,7 +2189,7 @@ namespace Local {
_storageWebFilesSize = 0;
_locationsKey = _reportSpamStatusesKey = 0;
_recentStickersKeyOld = _stickersKey = _savedGifsKey = 0;
_backgroundKey = _userSettingsKey = _recentHashtagsKey = _savedPeersKey = 0;
_backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = 0;
_oldMapVersion = _oldSettingsVersion = 0;
_mapChanged = true;
_writeMap(WriteMapNow);
@ -3258,89 +3260,6 @@ namespace Local {
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 result = sizeof(quint64) + sizeof(quint64) + _storageImageLocationSize();
if (peer->isUser()) {
@ -3370,7 +3289,7 @@ namespace Local {
return result;
}
void _writePeer(QDataStream &stream, PeerData *peer) {
void _writePeer(QDataStream &stream, PeerData *peer, int32 fileVersion = AppVersion) {
stream << quint64(peer->id) << quint64(peer->photoId);
_writeStorageImageLocation(stream, peer->photoLoc);
if (peer->isUser()) {
@ -3380,6 +3299,9 @@ namespace Local {
if (AppVersion >= 9012) {
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);
} else if (peer->isChat()) {
ChatData *chat = peer->asChat();
@ -3396,47 +3318,60 @@ namespace Local {
}
}
PeerData *_readPeer(FileReadDescriptor &from) {
PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) {
PeerData *result = 0;
quint64 peerId = 0, photoId = 0;
from.stream >> peerId >> photoId;
StorageImageLocation photoLoc(_readStorageImageLocation(from));
result = App::peer(peerId);
result->loaded = true;
result = App::peerLoaded(peerId);
bool wasLoaded = (result && result->loaded);
if (!wasLoaded) {
result = App::peer(peerId);
result->loaded = true;
}
if (result->isUser()) {
UserData *user = result->asUser();
QString first, last, phone, username;
QString first, last, phone, username, inlinePlaceholder;
quint64 access;
qint32 flags = 0, onlineTill, contact, botInfoVersion;
from.stream >> first >> last >> phone >> username >> access;
if (from.version >= 9012) {
from.stream >> flags;
}
if (from.version >= 9016 || fileVersion >= 9016) {
from.stream >> inlinePlaceholder;
}
from.stream >> onlineTill >> contact >> botInfoVersion;
bool showPhone = !isServiceUser(user->id) && (peerToUser(user->id) != MTP::authedId()) && (contact <= 0);
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->flags = flags;
user->onlineTill = onlineTill;
user->contact = contact;
user->setBotInfoVersion(botInfoVersion);
user->access = access;
user->flags = flags;
user->onlineTill = onlineTill;
user->contact = contact;
user->setBotInfoVersion(botInfoVersion);
if (!inlinePlaceholder.isEmpty() && user->botInfo) {
user->botInfo->inlinePlaceholder = inlinePlaceholder;
}
if (peerToUser(user->id) == MTP::authedId()) {
user->input = MTP_inputPeerSelf();
user->inputUser = MTP_inputUserSelf();
} else {
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));
if (peerToUser(user->id) == MTP::authedId()) {
user->input = MTP_inputPeerSelf();
user->inputUser = MTP_inputUserSelf();
} else {
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->photo = photoLoc.isNull() ? ImagePtr(userDefPhoto(user->colorIndex)) : ImagePtr(photoLoc);
}
user->photo = photoLoc.isNull() ? ImagePtr(userDefPhoto(user->colorIndex)) : ImagePtr(photoLoc);
} else if (result->isChat()) {
ChatData *chat = result->asChat();
@ -3450,19 +3385,21 @@ namespace Local {
// flagsData was haveLeft
flags = (flagsData == 1 ? MTPDchat::flag_left : 0);
}
chat->updateName(name, QString(), QString());
chat->count = count;
chat->date = date;
chat->version = version;
chat->creator = creator;
chat->isForbidden = (forbidden == 1);
chat->flags = flags;
chat->invitationUrl = invitationUrl;
if (!wasLoaded) {
chat->updateName(name, QString(), QString());
chat->count = count;
chat->date = date;
chat->version = version;
chat->creator = creator;
chat->isForbidden = (forbidden == 1);
chat->flags = flags;
chat->invitationUrl = invitationUrl;
chat->input = MTP_inputPeerChat(MTP_int(peerToChat(chat->id)));
chat->inputChat = MTP_int(peerToChat(chat->id));
chat->input = MTP_inputPeerChat(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()) {
ChannelData *channel = result->asChannel();
@ -3471,24 +3408,135 @@ namespace Local {
qint32 date, version, adminned, forbidden, flags;
from.stream >> name >> access >> date >> version >> forbidden >> flags >> invitationUrl;
channel->updateName(name, QString(), QString());
channel->access = access;
channel->date = date;
channel->version = version;
channel->isForbidden = (forbidden == 1);
channel->flags = flags;
channel->invitationUrl = invitationUrl;
if (!wasLoaded) {
channel->updateName(name, QString(), QString());
channel->access = access;
channel->date = date;
channel->version = version;
channel->isForbidden = (forbidden == 1);
channel->flags = flags;
channel->invitationUrl = invitationUrl;
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->input = MTP_inputPeerChannel(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;
}
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() {
if (!_working()) return;
@ -3594,6 +3642,7 @@ namespace Local {
struct ClearManagerData {
QThread *thread;
StorageMap images, stickers, audios;
WebFilesMap webFiles;
QMutex mutex;
QList<int> tasks;
bool working;
@ -3650,8 +3699,8 @@ namespace Local {
_stickersKey = 0;
_mapChanged = true;
}
if (_recentHashtagsKey) {
_recentHashtagsKey = 0;
if (_recentHashtagsAndBotsKey) {
_recentHashtagsAndBotsKey = 0;
_mapChanged = true;
}
if (_savedPeersKey) {
@ -3693,6 +3742,22 @@ namespace Local {
_storageStickersSize = 0;
_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()) {
data->audios = _audiosMap;
} else {
@ -3745,6 +3810,7 @@ namespace Local {
int task = 0;
bool result = false;
StorageMap images, stickers, audios;
WebFilesMap webFiles;
{
QMutexLocker lock(&data->mutex);
if (data->tasks.isEmpty()) {
@ -3755,6 +3821,7 @@ namespace Local {
images = data->images;
stickers = data->stickers;
audios = data->audios;
webFiles = data->webFiles;
}
switch (task) {
case ClearManagerAll: {
@ -3786,6 +3853,9 @@ namespace Local {
for (StorageMap::const_iterator i = audios.cbegin(), e = audios.cend(); i != e; ++i) {
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;
break;
}

View File

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

View File

@ -759,6 +759,10 @@ void MainWidget::notify_botCommandsChanged(UserData *bot) {
history.notify_botCommandsChanged(bot);
}
void MainWidget::notify_inlineBotRequesting(bool requesting) {
history.notify_inlineBotRequesting(requesting);
}
void MainWidget::notify_userIsBotChanged(UserData *bot) {
history.notify_userIsBotChanged(bot);
}
@ -1345,7 +1349,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
}
}
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
Local::readRecentHashtags();
Local::readRecentHashtagsAndBots();
recent = cRecentWriteHashtags();
}
found = true;
@ -1353,7 +1357,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
}
if (found) {
cSetRecentWriteHashtags(recent);
Local::writeRecentHashtags();
Local::writeRecentHashtagsAndBots();
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -453,9 +453,9 @@ void Window::firstShow() {
trayIconMenu = new QMenu(this);
trayIconMenu->setFont(QFont("Tahoma"));
#endif
QString notificationItem = lang(cDesktopNotify()
QString notificationItem = lang(cDesktopNotify()
? lng_disable_notifications_from_tray : lng_enable_notifications_from_tray);
if (cPlatform() == dbipWindows || cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()))->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 {
int x(p.x()), y(p.y()), w(width()), h(height());
const int32 raw = psResizeRowWidth();
if (!windowState().testFlag(Qt::WindowMaximized)) {
if (y < raw) {
@ -1019,7 +1019,7 @@ void Window::mouseMoveEvent(QMouseEvent *e) {
if (dragging) {
if (windowState().testFlag(Qt::WindowMaximized)) {
setWindowState(windowState() & ~Qt::WindowMaximized);
dragStart = e->globalPos() - frameGeometry().topLeft();
} else {
move(e->globalPos() - dragStart);
@ -1260,7 +1260,7 @@ Window::TempDirState Window::localStorageState() {
if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) {
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) {

View File

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

View File

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