mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-20 23:27:23 +00:00
Merge branch 'bots' of https://bitbucket.org/johnprestonmail/telegram-desktop into bots
This commit is contained in:
commit
8116334557
@ -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);
|
||||
|
@ -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 |
@ -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
|
||||
|
||||
|
@ -163,7 +163,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -121,6 +121,8 @@ int32 gSavedGifsLimit = 100;
|
||||
|
||||
RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags;
|
||||
|
||||
RecentInlineBots gRecentInlineBots;
|
||||
|
||||
bool gPasswordRecovered = false;
|
||||
int32 gPasscodeBadTries = 0;
|
||||
uint64 gPasscodeLastTry = 0;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -3,4 +3,4 @@ AppVersionStrMajor 0.9
|
||||
AppVersionStrSmall 0.9.15
|
||||
AppVersionStr 0.9.15
|
||||
DevChannel 0
|
||||
BetaVersion 9015005
|
||||
BetaVersion 9015006
|
||||
|
Loading…
Reference in New Issue
Block a user