stickers by alt suggestions in mentions dropdown

This commit is contained in:
John Preston 2016-01-09 19:24:16 +08:00
parent f66c54ee6b
commit a72a31e722
22 changed files with 471 additions and 149 deletions

View File

@ -430,7 +430,7 @@ void ApiWrap::requestBots(ChannelData *peer) {
void ApiWrap::gotChat(PeerData *peer, const MTPmessages_Chats &result) {
_peerRequests.remove(peer);
if (result.type() == mtpc_messages_chats) {
const QVector<MTPChat> &v(result.c_messages_chats().vchats.c_vector().v);
bool badVersion = false;
@ -682,10 +682,11 @@ void ApiWrap::requestStickerSets() {
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
_stickerSetRequests.remove(setId);
if (result.type() != mtpc_messages_stickerSet) return;
const MTPDmessages_stickerSet &d(result.c_messages_stickerSet());
const QVector<MTPStickerPack> &v(d.vpacks.c_vector().v);
if (d.vset.type() != mtpc_stickerSet) return;
const MTPDstickerSet &s(d.vset.c_stickerSet());
@ -731,12 +732,15 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
++i;
}
}
Global::StickersByEmoji_RemovePack(it->stickers);
if (pack.isEmpty()) {
int32 removeIndex = cStickerSetsOrder().indexOf(setId);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
sets.erase(it);
} else {
it->stickers = pack;
Global::StickersByEmoji_AddPack(it->stickers);
}
if (writeRecent) {

View File

@ -1969,6 +1969,7 @@ namespace App {
if (api()) api()->clearWebPageRequests();
cSetRecentStickers(RecentStickerPack());
cSetStickerSets(StickerSets());
Global::SetStickersByEmoji(StickersByEmojiMap());
cSetStickerSetsOrder(StickerSetsOrder());
cSetLastStickersUpdate(0);
cSetSavedGifs(SavedGifs());

View File

@ -50,7 +50,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
for (int32 i = 0, l = v.size(); i < l; ++i) {
DocumentData *doc = App::feedDocument(v.at(i));
if (!doc || !doc->sticker()) continue;
_pack.push_back(doc);
}
if (d.vset.type() == mtpc_stickerSet) {
@ -92,6 +92,7 @@ void StickerSetInner::installDone(const MTPBool &result) {
_setFlags &= ~MTPDstickerSet::flag_disabled;
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)).value().stickers = _pack;
Global::StickersByEmoji_AddPack(_pack);
StickerSetsOrder &order(cRefStickerSetsOrder());
int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId);
@ -507,7 +508,7 @@ void StickersInner::onUpdateSelected() {
float64 StickersInner::aboveShadowOpacity() const {
if (_above < 0) return 0;
int32 dx = 0;
int32 dy = qAbs(_above * _rowHeight + _rows.at(_above)->yadd.current() - _started * _rowHeight);
return qMin((dx + dy) * 2. / _rowHeight, 1.);
@ -613,7 +614,7 @@ void StickersInner::rebuild() {
clear();
const StickerSetsOrder &order(cStickerSetsOrder());
_animStartTimes.reserve(order.size());
const StickerSets &sets(cStickerSets());
for (int32 i = 0, l = order.size(); i < l; ++i) {
StickerSets::const_iterator it = sets.constFind(order.at(i));
@ -867,6 +868,7 @@ void StickersBox::onSave() {
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
sets.erase(it);
}
Global::StickersByEmoji_RemovePack(it->stickers);
}
}
}
@ -879,6 +881,7 @@ void StickersBox::onSave() {
MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
_disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolFalse()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType());
it->flags &= ~MTPDstickerSet::flag_disabled;
Global::StickersByEmoji_AddPack(it->stickers);
}
order.push_back(reorder.at(i));
}
@ -887,6 +890,7 @@ void StickersBox::onSave() {
if (it->id == CustomStickerSetId || it->id == RecentStickerSetId || order.contains(it->id)) {
++it;
} else {
Global::StickersByEmoji_RemovePack(it->stickers);
it = sets.erase(it);
}
}

View File

@ -3564,6 +3564,7 @@ void EmojiPan::onRemoveSetSure() {
Ui::hideLayer();
StickerSets::iterator it = cRefStickerSets().find(_removingSetId);
if (it != cRefStickerSets().cend() && !(it->flags & MTPDstickerSet::flag_official)) {
Global::StickersByEmoji_RemovePack(it->stickers);
if (it->id && it->access) {
MTP::send(MTPmessages_UninstallStickerSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access))));
} else if (!it->shortName.isEmpty()) {
@ -3841,24 +3842,74 @@ void EmojiPan::recountContentMaxHeight() {
updateContentHeight();
}
MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows)
MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerByEmojiRows *srows)
: _parent(parent)
, _mrows(mrows)
, _hrows(hrows)
, _brows(brows)
, _srows(srows)
, _stickersPerRow(1)
, _recentInlineBotsInRows(0)
, _sel(-1)
, _mouseSel(false)
, _overDelete(false) {
}
void MentionsInner::paintEvent(QPaintEvent *e) {
QPainter p(this);
Painter p(this);
QRect r(e->rect());
if (r != rect()) p.setClipRect(r);
int32 atwidth = st::mentionFont->width('@'), hashwidth = st::mentionFont->width('#');
int32 mentionleft = 2 * st::mentionPadding.left() + st::mentionPhotoSize;
int32 mentionwidth = width() - mentionleft - 2 * st::mentionPadding.right();
int32 htagleft = st::btnAttachPhoto.width + st::taMsgField.textMrg.left() - st::lineWidth, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width;
if (!_srows->isEmpty()) {
int32 rows = rowscount(_srows->size(), _stickersPerRow);
int32 fromrow = floorclamp(r.y() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
int32 torow = ceilclamp(r.y() + r.height() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
int32 fromcol = floorclamp(r.x() - st::stickerPanPadding, st::stickerPanSize.width(), 0, _stickersPerRow);
int32 tocol = ceilclamp(r.x() + r.width() - st::stickerPanPadding, st::stickerPanSize.width(), 0, _stickersPerRow);
for (int32 row = fromrow; row < torow; ++row) {
for (int32 col = fromcol; col < tocol; ++col) {
int32 index = row * _stickersPerRow + col;
if (index >= _srows->size()) break;
DocumentData *sticker = _srows->at(index);
if (!sticker->sticker()) continue;
QPoint pos(st::stickerPanPadding + col * st::stickerPanSize.width(), st::stickerPanPadding + row * st::stickerPanSize.height());
if (_sel == index) {
QPoint tl(pos);
if (rtl()) tl.setX(width() - tl.x() - st::stickerPanSize.width());
App::roundRect(p, QRect(tl, st::stickerPanSize), st::emojiPanHover, StickerHoverCorners);
}
bool goodThumb = !sticker->thumb->isNull() && ((sticker->thumb->width() >= 128) || (sticker->thumb->height() >= 128));
if (goodThumb) {
sticker->thumb->load();
} else {
sticker->checkSticker();
}
float64 coef = qMin((st::stickerPanSize.width() - st::msgRadius * 2) / float64(sticker->dimensions.width()), (st::stickerPanSize.height() - st::msgRadius * 2) / float64(sticker->dimensions.height()));
if (coef > 1) coef = 1;
int32 w = qRound(coef * sticker->dimensions.width()), h = qRound(coef * sticker->dimensions.height());
if (w < 1) w = 1;
if (h < 1) h = 1;
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
if (goodThumb) {
p.drawPixmapLeft(ppos, width(), sticker->thumb->pix(w, h));
} else if (!sticker->sticker()->img->isNull()) {
p.drawPixmapLeft(ppos, width(), sticker->sticker()->img->pix(w, h));
}
}
}
return;
}
int32 from = qFloor(e->rect().top() / st::mentionHeight), to = qFloor(e->rect().bottom() / st::mentionHeight) + 1;
int32 last = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size();
bool hasUsername = _parent->filter().indexOf('@') > 1;
@ -3970,6 +4021,10 @@ void MentionsInner::paintEvent(QPaintEvent *e) {
p.fillRect(cWideMode() ? st::lineWidth : 0, _parent->innerBottom() - st::lineWidth, width() - (cWideMode() ? st::lineWidth : 0), st::lineWidth, st::shadowColor->b);
}
void MentionsInner::resizeEvent(QResizeEvent *e) {
_stickersPerRow = int32(width() - 2 * st::stickerPanPadding) / int32(st::stickerPanSize.width());
}
void MentionsInner::mouseMoveEvent(QMouseEvent *e) {
_mousePos = mapToGlobal(e->pos());
_mouseSel = true;
@ -3978,29 +4033,47 @@ void MentionsInner::mouseMoveEvent(QMouseEvent *e) {
void MentionsInner::clearSel() {
_mouseSel = _overDelete = false;
setSel((_mrows->isEmpty() && _brows->isEmpty() && _hrows->isEmpty()) ? -1 : 0);
setSel((_mrows->isEmpty() && _brows->isEmpty() && _hrows->isEmpty() && _srows->isEmpty()) ? -1 : 0);
}
bool MentionsInner::moveSel(int direction) {
bool MentionsInner::moveSel(int key) {
_mouseSel = false;
int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size());
int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? (_brows->isEmpty() ? _srows->size() : _brows->size()) : _hrows->size()) : _mrows->size());
int32 direction = (key == Qt::Key_Up) ? -1 : (key == Qt::Key_Down ? 1 : 0);
if (!_srows->isEmpty()) {
if (key == Qt::Key_Left) {
direction = -1;
} else if (key == Qt::Key_Right) {
direction = 1;
} else {
direction *= _stickersPerRow;
}
}
if (_sel >= maxSel || _sel < 0) {
if (direction < 0) {
if (direction < -1) {
setSel(((maxSel - 1) / _stickersPerRow) * _stickersPerRow, true);
} else if (direction < 0) {
setSel(maxSel - 1, true);
} else {
setSel(0, true);
}
return (_sel >= 0 && _sel < maxSel);
}
setSel((_sel + direction >= maxSel) ? -1 : (_sel + direction), true);
setSel((_sel + direction >= maxSel || _sel + direction < 0) ? -1 : (_sel + direction), true);
return true;
}
bool MentionsInner::select() {
QString sel = getSelected();
if (!sel.isEmpty()) {
emit chosen(sel);
return true;
if (!_srows->isEmpty()) {
if (_sel >= 0 && _sel < _srows->size()) {
emit selected(_srows->at(_sel));
}
} else {
QString sel = getSelected();
if (!sel.isEmpty()) {
emit chosen(sel);
return true;
}
}
return false;
}
@ -4086,21 +4159,51 @@ void MentionsInner::leaveEvent(QEvent *e) {
}
}
void MentionsInner::updateSelectedRow() {
if (_sel >= 0) {
if (_srows->isEmpty()) {
update(0, _sel * st::mentionHeight, width(), st::mentionHeight);
} else {
int32 row = _sel / _stickersPerRow, col = _sel % _stickersPerRow;
update(st::stickerPanPadding + col * st::stickerPanSize.width(), st::stickerPanPadding + row * st::stickerPanSize.height(), st::stickerPanSize.width(), st::stickerPanSize.height());
}
}
}
void MentionsInner::setSel(int sel, bool scroll) {
if (_sel >= 0) update(0, _sel * st::mentionHeight, width(), st::mentionHeight);
updateSelectedRow();
_sel = sel;
if (_sel >= 0) update(0, _sel * st::mentionHeight, width(), st::mentionHeight);
int32 maxSel = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size();
if (scroll && _sel >= 0 && _sel < maxSel) emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight);
updateSelectedRow();
if (scroll && _sel >= 0) {
if (_srows->isEmpty()) {
emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight);
} else {
int32 row = _sel / _stickersPerRow;
emit mustScrollTo(st::stickerPanPadding + row * st::stickerPanSize.height(), st::stickerPanPadding + (row + 1) * st::stickerPanSize.height());
}
}
}
void MentionsInner::onUpdateSelected(bool force) {
QPoint mouse(mapFromGlobal(_mousePos));
if ((!force && !rect().contains(mouse)) || !_mouseSel) return;
int w = width(), mouseY = mouse.y();
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;
int32 sel = -1, maxSel = 0;
if (!_srows->isEmpty()) {
int32 rows = rowscount(_srows->size(), _stickersPerRow);
int32 row = (mouse.y() >= st::stickerPanPadding) ? ((mouse.y() - st::stickerPanPadding) / st::stickerPanSize.height()) : -1;
int32 col = (mouse.x() >= st::stickerPanPadding) ? ((mouse.x() - st::stickerPanPadding) / st::stickerPanSize.width()) : -1;
if (row >= 0 && col >= 0) {
sel = row * _stickersPerRow + col;
}
maxSel = _srows->size();
_overDelete = false;
} else {
sel = mouse.y() / int32(st::mentionHeight);
maxSel = _mrows->isEmpty() ? (_hrows->isEmpty() ? _brows->size() : _hrows->size()) : _mrows->size();
_overDelete = (!_hrows->isEmpty() || (!_mrows->isEmpty() && sel < _recentInlineBotsInRows)) ? (mouse.x() >= width() - st::mentionHeight) : false;
}
if (sel < 0 || sel >= maxSel) {
sel = -1;
}
@ -4119,7 +4222,7 @@ void MentionsInner::onParentGeometryChanged() {
MentionsDropdown::MentionsDropdown(QWidget *parent) : TWidget(parent)
, _scroll(this, st::mentionScroll)
, _inner(this, &_mrows, &_hrows, &_brows)
, _inner(this, &_mrows, &_hrows, &_brows, &_srows)
, _chat(0)
, _user(0)
, _channel(0)
@ -4130,6 +4233,7 @@ MentionsDropdown::MentionsDropdown(QWidget *parent) : TWidget(parent)
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
connect(&_inner, SIGNAL(chosen(QString)), this, SIGNAL(chosen(QString)));
connect(&_inner, SIGNAL(selected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
connect(App::wnd(), SIGNAL(imageLoaded()), &_inner, SLOT(update()));
@ -4150,7 +4254,7 @@ MentionsDropdown::MentionsDropdown(QWidget *parent) : TWidget(parent)
}
void MentionsDropdown::paintEvent(QPaintEvent *e) {
QPainter p(this);
Painter p(this);
if (_a_appearance.animating()) {
p.setOpacity(a_opacity.current());
@ -4158,29 +4262,43 @@ void MentionsDropdown::paintEvent(QPaintEvent *e) {
return;
}
p.fillRect(rect(), st::white->b);
p.fillRect(rect(), st::white);
}
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();
if (query.isEmpty()) {
rowsUpdated(MentionRows(), HashtagRows(), BotCommandRows(), _srows, false);
return;
}
_emoji = EmojiPtr();
query = query.toLower();
bool toDown = (_filter != query);
if (toDown) {
bool resetScroll = (_filter != query);
if (resetScroll) {
_filter = query;
}
_addInlineBots = start;
updateFiltered(toDown);
updateFiltered(resetScroll);
}
void MentionsDropdown::showStickers(EmojiPtr emoji) {
bool resetScroll = (_emoji != emoji);
_emoji = emoji;
if (!emoji) {
rowsUpdated(_mrows, _hrows, _brows, StickerByEmojiRows(), false);
return;
}
_chat = 0;
_user = 0;
_channel = 0;
updateFiltered(resetScroll);
}
bool MentionsDropdown::clearFilteredBotCommands() {
@ -4189,12 +4307,22 @@ bool MentionsDropdown::clearFilteredBotCommands() {
return true;
}
void MentionsDropdown::updateFiltered(bool toDown) {
void MentionsDropdown::updateFiltered(bool resetScroll) {
int32 now = unixtime(), recentInlineBots = 0;
MentionRows mrows;
HashtagRows hrows;
BotCommandRows brows;
if (_filter.at(0) == '@') {
StickerByEmojiRows srows;
if (_emoji) {
const StickersByEmojiMap &stickers(Global::StickersByEmoji());
StickersByEmojiMap::const_iterator it = stickers.constFind(emojiGetNoColor(_emoji));
if (it != stickers.cend() && !it->isEmpty()) {
srows.reserve(it->size());
for (StickersByEmojiList::const_iterator i = it->cbegin(), e = it->cend(); i != e; ++i) {
srows.push_back(i.key());
}
}
} else 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()) {
@ -4214,46 +4342,46 @@ void MentionsDropdown::updateFiltered(bool toDown) {
++recentInlineBots;
}
}
}
if (_filter.at(0) == '@' && _chat) {
QMultiMap<int32, UserData*> ordered;
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()) {
for (ChatData::Participants::const_iterator i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
UserData *user = i.key();
if (user->username.isEmpty()) continue;
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
ordered.insertMulti(App::onlineForSort(user, now), user);
if (_chat) {
QMultiMap<int32, UserData*> ordered;
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()) {
for (ChatData::Participants::const_iterator i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
UserData *user = i.key();
if (user->username.isEmpty()) continue;
if (_filter.size() > 1 && (!user->username.startsWith(_filter.midRef(1), Qt::CaseInsensitive) || user->username.size() + 1 == _filter.size())) continue;
ordered.insertMulti(App::onlineForSort(user, now), user);
}
}
}
for (MentionRows::const_iterator i = _chat->lastAuthors.cbegin(), e = _chat->lastAuthors.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);
if (!ordered.isEmpty()) {
ordered.remove(App::onlineForSort(user, now), user);
}
}
if (!ordered.isEmpty()) {
for (QMultiMap<int32, UserData*>::const_iterator i = ordered.cend(), b = ordered.cbegin(); i != b;) {
--i;
mrows.push_back(i.value());
}
}
} else if (_filter.at(0) == '@' && _channel && _channel->isMegagroup()) {
QMultiMap<int32, UserData*> ordered;
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
if (App::api()) App::api()->requestLastParticipants(_channel);
} else {
mrows.reserve(mrows.size() + _channel->mgInfo->lastParticipants.size());
for (MegagroupInfo::LastParticipants::const_iterator i = _channel->mgInfo->lastParticipants.cbegin(), e = _channel->mgInfo->lastParticipants.cend(); i != e; ++i) {
for (MentionRows::const_iterator i = _chat->lastAuthors.cbegin(), e = _chat->lastAuthors.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);
if (!ordered.isEmpty()) {
ordered.remove(App::onlineForSort(user, now), user);
}
}
if (!ordered.isEmpty()) {
for (QMultiMap<int32, UserData*>::const_iterator i = ordered.cend(), b = ordered.cbegin(); i != b;) {
--i;
mrows.push_back(i.value());
}
}
} else if (_channel && _channel->isMegagroup()) {
QMultiMap<int32, UserData*> ordered;
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
if (App::api()) App::api()->requestLastParticipants(_channel);
} else {
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;
mrows.push_back(user);
}
}
}
} else if (_filter.at(0) == '#') {
@ -4332,28 +4460,31 @@ void MentionsDropdown::updateFiltered(bool toDown) {
}
}
}
rowsUpdated(mrows, hrows, brows, toDown);
rowsUpdated(mrows, hrows, brows, srows, resetScroll);
_inner.setRecentInlineBotsInRows(recentInlineBots);
}
void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown) {
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty()) {
void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, const StickerByEmojiRows &srows, bool resetScroll) {
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.isEmpty()) {
if (!isHidden()) {
hideStart();
}
_mrows.clear();
_hrows.clear();
_brows.clear();
_srows.clear();
} else {
_mrows = mrows;
_hrows = hrows;
_brows = brows;
_srows = srows;
bool hidden = _hiding || isHidden();
if (hidden) {
show();
_scroll.show();
}
recount(toDown);
recount(resetScroll);
if (hidden) {
hide();
showStart();
@ -4363,31 +4494,37 @@ void MentionsDropdown::rowsUpdated(const MentionRows &mrows, const HashtagRows &
void MentionsDropdown::setBoundings(QRect boundings) {
_boundings = boundings;
resize(_boundings.width(), height());
_scroll.resize(size());
_inner.resize(width(), _inner.height());
recount();
}
void MentionsDropdown::recount(bool toDown) {
int32 h = (_mrows.isEmpty() ? (_hrows.isEmpty() ? _brows.size() : _hrows.size()) : _mrows.size()) * st::mentionHeight, oldst = _scroll.scrollTop(), st = oldst;
void MentionsDropdown::recount(bool resetScroll) {
int32 h = 0, oldst = _scroll.scrollTop(), st = oldst, maxh = 4.5 * st::mentionHeight;
if (!_srows.isEmpty()) {
int32 stickersPerRow = int32(_boundings.width() - 2 * st::stickerPanPadding) / int32(st::stickerPanSize.width());
int32 rows = rowscount(_srows.size(), stickersPerRow);
h = st::stickerPanPadding + rows * st::stickerPanSize.height();
} else if (!_mrows.isEmpty()) {
h = _mrows.size() * st::mentionHeight;
} else if (!_hrows.isEmpty()) {
h = _hrows.size() * st::mentionHeight;
} else if (!_brows.isEmpty()) {
h = _brows.size() * st::mentionHeight;
}
if (_inner.height() != h) {
// st += h - _inner.height();
_inner.resize(width(), h);
if (_inner.width() != _boundings.width() || _inner.height() != h) {
_inner.resize(_boundings.width(), h);
}
if (h > _boundings.height()) h = _boundings.height();
if (h > 4.5 * st::mentionHeight) h = 4.5 * st::mentionHeight;
if (height() != h) {
// st += _scroll.height() - h;
setGeometry(0, _boundings.height() - h, width(), h);
_scroll.resize(width(), h);
if (h > maxh) h = maxh;
if (width() != _boundings.width() || height() != h) {
setGeometry(0, _boundings.height() - h, _boundings.width(), h);
_scroll.resize(_boundings.width(), h);
} else if (y() != _boundings.height() - h) {
move(0, _boundings.height() - h);
}
if (toDown) st = 0;// _scroll.scrollTopMax();
if (resetScroll) st = 0;
if (st != oldst) _scroll.scrollToY(st);
if (toDown) _inner.clearSel();
if (resetScroll) _inner.clearSel();
}
void MentionsDropdown::fastHide() {
@ -4487,11 +4624,8 @@ bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
if (isHidden()) return QWidget::eventFilter(obj, e);
if (e->type() == QEvent::KeyPress) {
QKeyEvent *ev = static_cast<QKeyEvent*>(e);
if (ev->key() == Qt::Key_Up) {
_inner.moveSel(-1);
return true;
} else if (ev->key() == Qt::Key_Down) {
return _inner.moveSel(1);
if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down || (!_srows.isEmpty() && (ev->key() == Qt::Key_Left || ev->key() == Qt::Key_Right))) {
return _inner.moveSel(ev->key());
} else if (ev->key() == Qt::Key_Enter || ev->key() == Qt::Key_Return) {
return _inner.select();
}

View File

@ -727,6 +727,7 @@ private:
typedef QList<UserData*> MentionRows;
typedef QList<QString> HashtagRows;
typedef QList<QPair<UserData*, const BotCommand*> > BotCommandRows;
typedef QList<DocumentData*> StickerByEmojiRows;
class MentionsDropdown;
class MentionsInner : public TWidget {
@ -734,9 +735,10 @@ class MentionsInner : public TWidget {
public:
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows);
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerByEmojiRows *srows);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
@ -745,7 +747,7 @@ public:
void mouseMoveEvent(QMouseEvent *e);
void clearSel();
bool moveSel(int direction);
bool moveSel(int key);
bool select();
void setRecentInlineBotsInRows(int32 bots);
@ -755,6 +757,7 @@ public:
signals:
void chosen(QString mentionOrHashtag);
void selected(DocumentData *sticker);
void mustScrollTo(int scrollToTop, int scrollToBottom);
public slots:
@ -764,13 +767,15 @@ public slots:
private:
void updateSelectedRow();
void setSel(int sel, bool scroll = false);
MentionsDropdown *_parent;
MentionRows *_mrows;
HashtagRows *_hrows;
BotCommandRows *_brows;
int32 _recentInlineBotsInRows;
StickerByEmojiRows *_srows;
int32 _stickersPerRow, _recentInlineBotsInRows;
int32 _sel;
bool _mouseSel;
QPoint _mousePos;
@ -791,7 +796,8 @@ public:
bool clearFilteredBotCommands();
void showFiltered(PeerData *peer, QString query, bool start);
void updateFiltered(bool toDown = false);
void showStickers(EmojiPtr emoji);
void updateFiltered(bool resetScroll = false);
void setBoundings(QRect boundings);
void step_appearance(float64 ms, bool timer);
@ -807,6 +813,10 @@ public:
bool eventFilter(QObject *obj, QEvent *e);
QString getSelected() const;
bool stickersShown() const {
return !_srows.isEmpty();
}
bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
@ -818,6 +828,7 @@ public:
signals:
void chosen(QString mentionOrHashtag);
void stickerSelected(DocumentData *sticker);
public slots:
@ -828,14 +839,15 @@ public slots:
private:
void recount(bool toDown = false);
void recount(bool resetScroll = false);
QPixmap _cache;
MentionRows _mrows;
HashtagRows _hrows;
BotCommandRows _brows;
StickerByEmojiRows _srows;
void rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown);
void rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, const StickerByEmojiRows &srows, bool resetScroll);
ScrollArea _scroll;
MentionsInner _inner;
@ -843,6 +855,7 @@ private:
ChatData *_chat;
UserData *_user;
ChannelData *_channel;
EmojiPtr _emoji;
QString _filter;
QRect _boundings;
bool _addInlineBots;

View File

@ -174,3 +174,83 @@ namespace Notify {
}
}
namespace Global {
struct Data {
uint64 LaunchId;
StickersByEmojiMap StickersByEmoji;
};
Data *_data = 0;
Initializer::Initializer() {
initThirdParty();
_data = new Data();
memset_rand(&_data->LaunchId, sizeof(_data->LaunchId));
}
Initializer::~Initializer() {
deinitThirdParty();
}
#define DefineGlobalReadOnly(Type, Name) const Type &Name() { \
t_assert_full(_data != 0, "_data is null in Global::" #Name, __FILE__, __LINE__); \
return _data->Name; \
}
#define DefineGlobal(Type, Name) DefineGlobalReadOnly(Type, Name) \
void Set##Name(const Type &Name) { \
t_assert_full(_data != 0, "_data is null in Global::Set" #Name, __FILE__, __LINE__); \
_data->Name = Name; \
} \
Type &Ref##Name() { \
t_assert_full(_data != 0, "_data is null in Global::Ref" #Name, __FILE__, __LINE__); \
return _data->Name; \
}
DefineGlobalReadOnly(uint64, LaunchId);
DefineGlobal(StickersByEmojiMap, StickersByEmoji);
void StickersByEmoji_Add(DocumentData *doc) {
if (StickerData *sticker = doc->sticker()) {
if (EmojiPtr emoji = emojiGetNoColor(emojiFromText(sticker->alt))) {
RefStickersByEmoji()[emoji].insert(doc);
}
}
}
bool StickersByEmoji_Remove(DocumentData *doc) {
if (StickerData *sticker = doc->sticker()) {
if (EmojiPtr emoji = emojiGetNoColor(emojiFromText(sticker->alt))) {
StickersByEmojiMap stickers(RefStickersByEmoji());
StickersByEmojiMap::iterator iList = stickers.find(emoji);
if (iList != stickers.cend()) {
StickersByEmojiList::iterator iEntry = iList->find(doc);
if (iEntry != iList->cend()) {
iList->erase(iEntry);
if (iList->isEmpty()) {
stickers.erase(iList);
}
return true;
}
}
}
}
return false;
}
void StickersByEmoji_AddPack(const StickerPack &pack) {
for (StickerPack::const_iterator i = pack.cbegin(), e = pack.cend(); i != e; ++i) {
StickersByEmoji_Add(*i);
}
}
void StickersByEmoji_RemovePack(const StickerPack &pack) {
for (StickerPack::const_iterator i = pack.cbegin(), e = pack.cend(); i != e; ++i) {
StickersByEmoji_Remove(*i);
}
}
};

View File

@ -95,3 +95,29 @@ namespace Notify {
void automaticLoadSettingsChangedGif();
};
typedef OrderedSet<DocumentData*> StickersByEmojiList;
typedef QMap<EmojiPtr, StickersByEmojiList> StickersByEmojiMap;
namespace Global {
class Initializer {
public:
Initializer();
~Initializer();
};
#define DeclareGlobalReadOnly(Type, Name) const Type &Name();
#define DeclareGlobal(Type, Name) DeclareGlobalReadOnly(Type, Name) \
void Set##Name(const Type &Name); \
Type &Ref##Name();
DeclareGlobalReadOnly(uint64, LaunchId);
DeclareGlobal(StickersByEmojiMap, StickersByEmoji);
void StickersByEmoji_Add(DocumentData *doc);
bool StickersByEmoji_Remove(DocumentData *doc);
void StickersByEmoji_AddPack(const StickerPack &pack);
void StickersByEmoji_RemovePack(const StickerPack &pack);
};

View File

@ -83,7 +83,7 @@ inline EmojiPtr emojiFromUrl(const QString &url) {
return emojiFromKey(url.midRef(10).toULongLong(0, 16)); // skip emoji://e.
}
inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int *plen = 0) {
EmojiPtr emoji = 0;
if (ch + 1 < e && ((ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) || (((ch->unicode() >= 0x30 && ch->unicode() < 0x3A) || ch->unicode() == 0x23 || ch->unicode() == 0x2A) && (ch + 1)->unicode() == 0x20E3))) {
uint32 code = (ch->unicode() << 16) | (ch + 1)->unicode();
@ -108,15 +108,15 @@ inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
} else if (ch + 2 < e && ((ch->unicode() >= 0x30 && ch->unicode() < 0x3A) || ch->unicode() == 0x23 || ch->unicode() == 0x2A) && (ch + 1)->unicode() == 0xFE0F && (ch + 2)->unicode() == 0x20E3) {
uint32 code = (ch->unicode() << 16) | (ch + 2)->unicode();
emoji = emojiGet(code);
len = emoji->len + 1;
if (plen) *plen = emoji->len + 1;
return emoji;
} else if (ch < e) {
emoji = emojiGet(ch->unicode());
Q_ASSERT(emoji != TwoSymbolEmoji);
t_assert(emoji != TwoSymbolEmoji);
}
if (emoji) {
len = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
int32 len = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
if (emoji->color && (ch + len + 1 < e && (ch + len)->isHighSurrogate() && (ch + len + 1)->isLowSurrogate())) { // color
uint32 color = ((uint32((ch + len)->unicode()) << 16) | uint32((ch + len + 1)->unicode()));
EmojiPtr col = emojiGet(emoji, color);
@ -128,8 +128,21 @@ inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
}
}
}
if (plen) *plen = len;
}
return emoji;
}
inline EmojiPtr emojiFromText(const QString &text, int32 *plen = 0) {
return text.isEmpty() ? EmojiPtr(0) : emojiFromText(text.constBegin(), text.constEnd(), plen);
}
inline EmojiPtr emojiGetNoColor(EmojiPtr emoji) {
if (emoji && emoji->color && (emoji->color & 0xFFFF0000U) != 0xFFFF0000U) {
EmojiPtr result = emojiGet(emoji->code);
return (result == TwoSymbolEmoji) ? emojiGet(emoji->code, emoji->code2) : result;
}
return emoji;
}
@ -180,7 +193,7 @@ inline QString replaceEmojis(const QString &text, EntitiesInText &entities) {
if (canFindEmoji) {
emojiFind(ch, e, newEmojiEnd, emojiCode);
}
while (currentEntity < entitiesCount && ch >= emojiStart + entities[currentEntity].offset + entities[currentEntity].length) {
++currentEntity;
}

View File

@ -66,7 +66,7 @@ FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString
, _notingBene(0)
, _st(st) {
resize(_st.width, _st.height);
setFont(_st.font->f);
setAlignment(_st.align);
@ -959,7 +959,7 @@ void InputArea::processDocumentContentsChange(int position, int charsAdded) {
const QChar *ch = t.constData(), *e = ch + t.size();
for (; ch != e; ++ch, ++fp) {
int32 emojiLen = 0;
emoji = emojiFromText(ch, e, emojiLen);
emoji = emojiFromText(ch, e, &emojiLen);
if (emoji) {
if (replacePosition >= 0) {
emoji = 0; // replace tilde char format first
@ -1331,7 +1331,7 @@ InputField::InputField(QWidget *parent, const style::InputField &st, const QStri
connect(&_inner, SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool)));
connect(&_inner, SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool)));
if (App::wnd()) connect(&_inner, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
setCursor(style::cur_text);
if (!val.isEmpty()) {
_inner.setPlainText(val);
@ -1412,7 +1412,7 @@ void InputField::paintEvent(QPaintEvent *e) {
if (_st.iconSprite.pxWidth()) {
p.drawSpriteLeft(_st.iconPosition, width(), _st.iconSprite);
}
bool drawPlaceholder = _placeholderVisible;
if (_a_placeholderShift.animating()) {
p.setOpacity(a_placeholderOpacity.current());
@ -1425,11 +1425,11 @@ void InputField::paintEvent(QPaintEvent *e) {
QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
r.moveLeft(r.left() + a_placeholderLeft.current());
if (rtl()) r.moveLeft(width() - r.left() - r.width());
p.setFont(_st.font);
p.setPen(a_placeholderFg.current());
p.drawText(r, _placeholder, _st.placeholderAlign);
p.restore();
}
TWidget::paintEvent(e);
@ -1663,7 +1663,7 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) {
}
int32 emojiLen = 0;
emoji = emojiFromText(ch, e, emojiLen);
emoji = emojiFromText(ch, e, &emojiLen);
if (emoji) {
if (replacePosition >= 0) {
emoji = 0; // replace tilde char format first
@ -2028,7 +2028,7 @@ MaskedInputField::MaskedInputField(QWidget *parent, const style::InputField &st,
setStyle(&_inputFieldStyle);
QLineEdit::setTextMargins(0, 0, 0, 0);
setContentsMargins(0, 0, 0, 0);
setAttribute(Qt::WA_AcceptTouchEvents);
_touchTimer.setSingleShot(true);
connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));

View File

@ -738,7 +738,7 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
const QChar *ch = t.constData(), *e = ch + t.size();
for (; ch != e; ++ch, ++fp) {
int32 emojiLen = 0;
emoji = emojiFromText(ch, e, emojiLen);
emoji = emojiFromText(ch, e, &emojiLen);
if (emoji) {
if (replacePosition >= 0) {
emoji = 0; // replace tilde char format first

View File

@ -598,7 +598,7 @@ public:
void parseEmojiFromCurrent() {
int len = 0;
EmojiPtr e = emojiFromText(ptr - emojiLookback, end, len);
EmojiPtr e = emojiFromText(ptr - emojiLookback, end, &len);
if (!e) return;
for (int l = len - emojiLookback - 1; l > 0; --l) {
@ -4502,8 +4502,7 @@ goodCanBreakEntity = canBreakEntity;\
#undef MARK_GOOD_AS_LEVEL
int elen = 0;
EmojiPtr e = emojiFromText(ch, end, elen);
if (e) {
if (EmojiPtr e = emojiFromText(ch, end, &elen)) {
for (int i = 0; i < elen; ++i, ++ch, ++s) {
if (ch->isHighSurrogate() && i + 1 < elen && (ch + 1)->isLowSurrogate()) {
++ch;

View File

@ -4744,14 +4744,11 @@ bool HistoryGif::dataLoaded() const {
HistorySticker::HistorySticker(DocumentData *document) : HistoryMedia()
, _pixw(1)
, _pixh(1)
, _data(document) {
, _data(document)
, _emoji(_data->sticker()->alt) {
_data->thumb->load();
if (!_data->sticker()->alt.isEmpty()) {
_emoji = _data->sticker()->alt;
int32 elen = 0;
if (EmojiPtr e = emojiFromText(_emoji.constData(), _emoji.constEnd(), elen)) {
_emoji = emojiString(e);
}
if (EmojiPtr e = emojiFromText(_emoji)) {
_emoji = emojiString(e);
}
}

View File

@ -2763,6 +2763,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
_attachMention.hide();
connect(&_attachMention, SIGNAL(chosen(QString)), this, SLOT(onMentionHashtagOrBotCommandInsert(QString)));
connect(&_attachMention, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
_field.installEventFilter(&_attachMention);
_field.setCtrlEnterSubmit(cCtrlEnter());
@ -2807,7 +2808,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
}
void HistoryWidget::start() {
connect(App::main(), SIGNAL(stickersUpdated()), &_emojiPan, SLOT(refreshStickers()));
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
connect(App::main(), SIGNAL(savedGifsUpdated()), &_emojiPan, SLOT(refreshSavedGifs()));
updateRecentStickers();
@ -2816,6 +2817,11 @@ void HistoryWidget::start() {
connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*)));
}
void HistoryWidget::onStickersUpdated() {
_emojiPan.refreshStickers();
updateStickersByEmoji();
}
void HistoryWidget::onMentionHashtagOrBotCommandInsert(QString str) {
if (str.at(0) == '/') { // bot command
App::sendBotCommand(str);
@ -2867,8 +2873,23 @@ void HistoryWidget::updateInlineBotQuery() {
}
}
void HistoryWidget::updateStickersByEmoji() {
int32 len = 0;
if (EmojiPtr emoji = emojiFromText(_field.getLastText(), &len)) {
if (_field.getLastText().size() <= len) {
_attachMention.showStickers(emoji);
} else {
len = 0;
}
}
if (!len) {
_attachMention.showStickers(EmojiPtr(0));
}
}
void HistoryWidget::onTextChange() {
updateInlineBotQuery();
updateStickersByEmoji();
if (_peer && (!_peer->isChannel() || _peer->isMegagroup() || !_peer->asChannel()->canPublish() || (!_peer->asChannel()->isBroadcast() && !_broadcast.checked()))) {
if (!_inlineBot && (_textUpdateEventsFlags & TextUpdateEventsSendTyping)) {
@ -3180,6 +3201,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
++i;
}
}
Global::StickersByEmoji_RemovePack(it->stickers);
it = sets.erase(it);
}
}
@ -5405,10 +5427,10 @@ void HistoryWidget::onFieldFocused() {
}
void HistoryWidget::onCheckMentionDropdown() {
if (!_history || _a_show.animating() || _inlineBot) return;
if (!_history || _a_show.animating()) return;
bool start = false;
QString query = _field.getMentionHashtagBotCommandPart(start);
QString query = _inlineBot ? QString() : _field.getMentionHashtagBotCommandPart(start);
if (!query.isEmpty()) {
if (query.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtagsAndBots();
if (query.at(0) == '@' && cRecentInlineBots().isEmpty()) Local::readRecentHashtagsAndBots();
@ -6529,6 +6551,13 @@ void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
App::historyRegRandom(randomId, newId);
if (_attachMention.stickersShown()) {
setFieldText(QString());
_saveDraftText = true;
_saveDraftStart = getms();
onDraftSave();
}
if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
@ -6813,7 +6842,9 @@ void HistoryWidget::updatePreview() {
void HistoryWidget::onCancel() {
if (_inlineBot && _field.getLastText().startsWith('@' + _inlineBot->username + ' ')) {
setFieldText(QString(), TextUpdateEventsSaveDraft, false);
} else {
} else if (!_attachMention.isHidden()) {
_attachMention.hideStart();
} else {
Ui::showChatsList();
emit cancelled();
}

View File

@ -452,6 +452,7 @@ public:
void updateFieldPlaceholder();
void updateInlineBotQuery();
void updateStickersByEmoji();
void uploadImage(const QImage &img, PrepareMediaType type, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &source = QString(), bool withText = false);
void uploadFile(const QString &file, PrepareMediaType type, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, bool withText = false); // with confirmation
@ -643,6 +644,7 @@ public slots:
void onCmdStart();
void activate();
void onStickersUpdated();
void onMentionHashtagOrBotCommandInsert(QString str);
void onTextChange();

View File

@ -2920,6 +2920,8 @@ namespace Local {
RecentStickerPack &recent(cRefRecentStickers());
recent.clear();
Global::SetStickersByEmoji(StickersByEmojiMap());
StickerSet &def(sets.insert(DefaultStickerSetId, StickerSet(DefaultStickerSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::flag_official)).value());
StickerSet &custom(sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, 0)).value());
@ -2993,6 +2995,8 @@ namespace Local {
StickerSetsOrder &order(cRefStickerSetsOrder());
order.clear();
Global::SetStickersByEmoji(StickersByEmojiMap());
quint32 cnt;
QByteArray hash;
stickers.stream >> cnt >> hash; // ignore hash, it is counted
@ -3073,6 +3077,10 @@ namespace Local {
set.stickers.push_back(doc);
++set.count;
}
if (setId != CustomStickerSetId) {
Global::StickersByEmoji_AddPack(set.stickers);
}
}
}

View File

@ -84,11 +84,13 @@ void logWrite(const QString &v);
static volatile int *t_assert_nullptr = 0;
inline void t_noop() {}
inline void t_assert_fail(const char *condition, const char *file, int32 line) {
LOG(("Assertion Failed! \"%1\" %2:%3").arg(condition).arg(file).arg(line));
inline void t_assert_fail(const char *message, const char *file, int32 line) {
LOG(("Assertion Failed! %1 %2:%3").arg(message).arg(file).arg(line));
*t_assert_nullptr = 0;
}
#define t_assert(cond) ((!(cond)) ? t_assert_fail(#cond, __FILE__, __LINE__) : t_noop())
#define t_assert_full(condition, message, file, line) ((!(condition)) ? t_assert_fail(message, file, line) : t_noop())
#define t_assert_c(condition, comment) t_assert_full(condition, "\"" #condition "\" (" comment ")", __FILE__, __LINE__)
#define t_assert(condition) t_assert_full(condition, "\"" #condition "\"", __FILE__, __LINE__)
void logsInit();
void logsInitDebug();

View File

@ -32,8 +32,6 @@ int main(int argc, char *argv[]) {
//signal(SIGSEGV, _sigsegvHandler);
#endif
LibrariesInitializer _init;
settingsParseArgs(argc, argv);
for (int32 i = 0; i < argc; ++i) {
if (string("-fixprevious") == argv[i]) {
@ -44,6 +42,8 @@ int main(int argc, char *argv[]) {
}
logsInit();
Global::Initializer _init;
Local::readSettings();
if (Local::oldSettingsVersion() < AppVersion) {
psNewVersion();

View File

@ -4607,8 +4607,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
const MTPDstickerSet &s(set.vset.c_stickerSet());
StickerSets &sets(cRefStickerSets());
sets.insert(s.vid.v, StickerSet(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v)).value().stickers = pack;
StickerSets::iterator it = sets.find(s.vid.v);
if (it != sets.cend()) {
Global::StickersByEmoji_RemovePack(it->stickers);
} else {
it = sets.insert(s.vid.v, StickerSet(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v));
}
it->stickers = pack;
Global::StickersByEmoji_AddPack(pack);
StickerSetsOrder &order(cRefStickerSetsOrder());
int32 insertAtIndex = 0, currentIndex = order.indexOf(s.vid.v);

View File

@ -190,7 +190,6 @@ void settingsParseArgs(int argc, char *argv[]) {
gCustomNotifies = false;
}
#endif
memset_rand(&gInstance, sizeof(gInstance));
gExeDir = psCurrentExeDirectory(argc, argv);
gExeName = psCurrentExeName(argc, argv);
for (int32 i = 0; i < argc; ++i) {

View File

@ -1513,6 +1513,8 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
_additional = 0;
} break;
case mtpc_documentAttributeSticker: {
bool wasByEmoji = Global::StickersByEmoji_Remove(this);
const MTPDdocumentAttributeSticker &d(attributes[i].c_documentAttributeSticker());
if (type == FileDocument) {
type = StickerDocument;
@ -1522,6 +1524,7 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
if (sticker()) {
sticker()->alt = qs(d.valt);
sticker()->set = d.vstickerset;
if (wasByEmoji) Global::StickersByEmoji_Add(this);
}
} break;
case mtpc_documentAttributeVideo: {

View File

@ -264,7 +264,7 @@ namespace {
_MsStarter _msStarter;
}
LibrariesInitializer::LibrariesInitializer() {
void initThirdParty() {
if (!RAND_status()) { // should be always inited in all modern OS
char buf[16];
memcpy(buf, &_msStart, 8);
@ -296,7 +296,7 @@ LibrariesInitializer::LibrariesInitializer() {
_sslInited = true;
}
LibrariesInitializer::~LibrariesInitializer() {
void deinitThirdParty() {
av_lockmgr_register(0);
delete[] _sslLocks;

View File

@ -133,11 +133,8 @@ inline void mylocaltime(struct tm * _Tm, const time_t * _Time) {
#endif
}
class LibrariesInitializer {
public:
LibrariesInitializer();
~LibrariesInitializer();
};
void initThirdParty(); // called by Global::Initializer
void deinitThirdParty();
bool checkms(); // returns true if time has changed
uint64 getms(bool checked = false);
@ -458,6 +455,9 @@ MimeType mimeTypeForName(const QString &mime);
MimeType mimeTypeForFile(const QFileInfo &file);
MimeType mimeTypeForData(const QByteArray &data);
inline int32 rowscount(int32 count, int32 perrow) {
return (count + perrow - 1) / perrow;
}
inline int32 floorclamp(int32 value, int32 step, int32 lowest, int32 highest) {
return qMin(qMax(value / step, lowest), highest);
}