Improve sticker by emoji ordering.

First display recent by send/install date, then trending, then other.
This commit is contained in:
John Preston 2018-03-08 00:25:03 +03:00
parent ccef155f7a
commit 90179188b9
7 changed files with 178 additions and 54 deletions

View File

@ -2200,6 +2200,10 @@ void ApiWrap::updateStickers() {
requestSavedGifs(now); requestSavedGifs(now);
} }
void ApiWrap::requestRecentStickersForce() {
requestRecentStickersWithHash(0);
}
void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) { void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) {
Expects(megagroup->mgInfo != nullptr); Expects(megagroup->mgInfo != nullptr);
@ -2283,13 +2287,19 @@ void ApiWrap::requestStickers(TimeId now) {
} }
void ApiWrap::requestRecentStickers(TimeId now) { void ApiWrap::requestRecentStickers(TimeId now) {
if (!_session->data().recentStickersUpdateNeeded(now) if (!_session->data().recentStickersUpdateNeeded(now)) {
|| _recentStickersUpdateRequest) { return;
}
requestRecentStickersWithHash(Local::countRecentStickersHash());
}
void ApiWrap::requestRecentStickersWithHash(int32 hash) {
if (_recentStickersUpdateRequest) {
return; return;
} }
_recentStickersUpdateRequest = request(MTPmessages_GetRecentStickers( _recentStickersUpdateRequest = request(MTPmessages_GetRecentStickers(
MTP_flags(0), MTP_flags(0),
MTP_int(Local::countRecentStickersHash()) MTP_int(hash)
)).done([=](const MTPmessages_RecentStickers &result) { )).done([=](const MTPmessages_RecentStickers &result) {
_session->data().setLastRecentStickersUpdate(getms(true)); _session->data().setLastRecentStickersUpdate(getms(true));
_recentStickersUpdateRequest = 0; _recentStickersUpdateRequest = 0;

View File

@ -126,6 +126,7 @@ public:
const Stickers::Order &localOrder, const Stickers::Order &localOrder,
const Stickers::Order &localRemoved); const Stickers::Order &localRemoved);
void updateStickers(); void updateStickers();
void requestRecentStickersForce();
void setGroupStickerSet( void setGroupStickerSet(
not_null<ChannelData*> megagroup, not_null<ChannelData*> megagroup,
const MTPInputStickerSet &set); const MTPInputStickerSet &set);
@ -345,6 +346,7 @@ private:
void requestStickers(TimeId now); void requestStickers(TimeId now);
void requestRecentStickers(TimeId now); void requestRecentStickers(TimeId now);
void requestRecentStickersWithHash(int32 hash);
void requestFavedStickers(TimeId now); void requestFavedStickers(TimeId now);
void requestFeaturedStickers(TimeId now); void requestFeaturedStickers(TimeId now);
void requestSavedGifs(TimeId now); void requestSavedGifs(TimeId now);

View File

@ -101,7 +101,7 @@ void FieldAutocomplete::showStickers(EmojiPtr emoji) {
_emoji = emoji; _emoji = emoji;
_type = Type::Stickers; _type = Type::Stickers;
if (!emoji) { if (!emoji) {
rowsUpdated(_mrows, _hrows, _brows, Stickers::Pack(), false); rowsUpdated(_mrows, _hrows, _brows, internal::StickerRows(), false);
return; return;
} }
@ -135,9 +135,9 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
internal::MentionRows mrows; internal::MentionRows mrows;
internal::HashtagRows hrows; internal::HashtagRows hrows;
internal::BotCommandRows brows; internal::BotCommandRows brows;
Stickers::Pack srows; internal::StickerRows srows;
if (_emoji) { if (_emoji) {
srows = Stickers::GetListByEmoji(_emoji); srows = Stickers::GetListByEmoji(_emoji, _stickersSeed);
} else if (_type == Type::Mentions) { } else if (_type == Type::Mentions) {
int maxListSize = _addInlineBots ? cRecentInlineBots().size() : 0; int maxListSize = _addInlineBots ? cRecentInlineBots().size() : 0;
if (_chat) { if (_chat) {
@ -319,8 +319,8 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
_inner->setRecentInlineBotsInRows(recentInlineBots); _inner->setRecentInlineBotsInRows(recentInlineBots);
} }
void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const Stickers::Pack &srows, bool resetScroll) { void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const internal::StickerRows &srows, bool resetScroll) {
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.isEmpty()) { if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.empty()) {
if (!isHidden()) { if (!isHidden()) {
hideAnimated(); hideAnimated();
} }
@ -356,7 +356,7 @@ void FieldAutocomplete::setBoundings(QRect boundings) {
void FieldAutocomplete::recount(bool resetScroll) { void FieldAutocomplete::recount(bool resetScroll) {
int32 h = 0, oldst = _scroll->scrollTop(), st = oldst, maxh = 4.5 * st::mentionHeight; int32 h = 0, oldst = _scroll->scrollTop(), st = oldst, maxh = 4.5 * st::mentionHeight;
if (!_srows.isEmpty()) { if (!_srows.empty()) {
int32 stickersPerRow = qMax(1, int32(_boundings.width() - 2 * st::stickerPanPadding) / int32(st::stickerPanSize.width())); int32 stickersPerRow = qMax(1, int32(_boundings.width() - 2 * st::stickerPanPadding) / int32(st::stickerPanSize.width()));
int32 rows = rowscount(_srows.size(), stickersPerRow); int32 rows = rowscount(_srows.size(), stickersPerRow);
h = st::stickerPanPadding + rows * st::stickerPanSize.height(); h = st::stickerPanPadding + rows * st::stickerPanSize.height();
@ -416,6 +416,7 @@ void FieldAutocomplete::showAnimated() {
return; return;
} }
if (_cache.isNull()) { if (_cache.isNull()) {
_stickersSeed = rand_value<uint64>();
_scroll->show(); _scroll->show();
_cache = Ui::GrabWidget(this); _cache = Ui::GrabWidget(this);
} }
@ -477,7 +478,7 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) {
QKeyEvent *ev = static_cast<QKeyEvent*>(e); QKeyEvent *ev = static_cast<QKeyEvent*>(e);
if (!(ev->modifiers() & (Qt::AltModifier | Qt::ControlModifier | Qt::ShiftModifier | Qt::MetaModifier))) { if (!(ev->modifiers() & (Qt::AltModifier | Qt::ControlModifier | Qt::ShiftModifier | Qt::MetaModifier))) {
if (!hidden) { if (!hidden) {
if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down || (!_srows.isEmpty() && (ev->key() == Qt::Key_Left || ev->key() == Qt::Key_Right))) { if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down || (!_srows.empty() && (ev->key() == Qt::Key_Left || ev->key() == Qt::Key_Right))) {
return _inner->moveSel(ev->key()); return _inner->moveSel(ev->key());
} else if (ev->key() == Qt::Key_Enter || ev->key() == Qt::Key_Return) { } else if (ev->key() == Qt::Key_Enter || ev->key() == Qt::Key_Return) {
return _inner->chooseSelected(ChooseMethod::ByEnter); return _inner->chooseSelected(ChooseMethod::ByEnter);
@ -498,7 +499,7 @@ FieldAutocomplete::~FieldAutocomplete() {
namespace internal { namespace internal {
FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, Stickers::Pack *srows) FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerRows *srows)
: _parent(parent) : _parent(parent)
, _mrows(mrows) , _mrows(mrows)
, _hrows(hrows) , _hrows(hrows)
@ -527,7 +528,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
int32 mentionwidth = width() - mentionleft - 2 * st::mentionPadding.right(); int32 mentionwidth = width() - mentionleft - 2 * st::mentionPadding.right();
int32 htagleft = st::historyAttach.width + st::historyComposeField.textMrg.left() - st::lineWidth, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width; int32 htagleft = st::historyAttach.width + st::historyComposeField.textMrg.left() - st::lineWidth, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width;
if (!_srows->isEmpty()) { if (!_srows->empty()) {
int32 rows = rowscount(_srows->size(), _stickersPerRow); int32 rows = rowscount(_srows->size(), _stickersPerRow);
int32 fromrow = floorclamp(r.y() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows); 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 torow = ceilclamp(r.y() + r.height() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
@ -697,7 +698,7 @@ bool FieldAutocompleteInner::moveSel(int key) {
_mouseSel = false; _mouseSel = false;
int32 maxSel = (_mrows->isEmpty() ? (_hrows->isEmpty() ? (_brows->isEmpty() ? _srows->size() : _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); int32 direction = (key == Qt::Key_Up) ? -1 : (key == Qt::Key_Down ? 1 : 0);
if (!_srows->isEmpty()) { if (!_srows->empty()) {
if (key == Qt::Key_Left) { if (key == Qt::Key_Left) {
direction = -1; direction = -1;
} else if (key == Qt::Key_Right) { } else if (key == Qt::Key_Right) {
@ -721,7 +722,7 @@ bool FieldAutocompleteInner::moveSel(int key) {
} }
bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const { bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const {
if (!_srows->isEmpty()) { if (!_srows->empty()) {
if (_sel >= 0 && _sel < _srows->size()) { if (_sel >= 0 && _sel < _srows->size()) {
emit stickerChosen(_srows->at(_sel), method); emit stickerChosen(_srows->at(_sel), method);
return true; return true;
@ -791,7 +792,7 @@ void FieldAutocompleteInner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true; _mouseSel = true;
onUpdateSelected(true); onUpdateSelected(true);
} else if (_srows->isEmpty()) { } else if (_srows->empty()) {
chooseSelected(FieldAutocomplete::ChooseMethod::ByClick); chooseSelected(FieldAutocomplete::ChooseMethod::ByClick);
} else { } else {
_down = _sel; _down = _sel;
@ -815,7 +816,7 @@ void FieldAutocompleteInner::mouseReleaseEvent(QMouseEvent *e) {
return; return;
} }
if (_sel < 0 || _sel != pressed || _srows->isEmpty()) return; if (_sel < 0 || _sel != pressed || _srows->empty()) return;
chooseSelected(FieldAutocomplete::ChooseMethod::ByClick); chooseSelected(FieldAutocomplete::ChooseMethod::ByClick);
} }
@ -835,7 +836,7 @@ void FieldAutocompleteInner::leaveEventHook(QEvent *e) {
void FieldAutocompleteInner::updateSelectedRow() { void FieldAutocompleteInner::updateSelectedRow() {
if (_sel >= 0) { if (_sel >= 0) {
if (_srows->isEmpty()) { if (_srows->empty()) {
update(0, _sel * st::mentionHeight, width(), st::mentionHeight); update(0, _sel * st::mentionHeight, width(), st::mentionHeight);
} else { } else {
int32 row = _sel / _stickersPerRow, col = _sel % _stickersPerRow; int32 row = _sel / _stickersPerRow, col = _sel % _stickersPerRow;
@ -850,7 +851,7 @@ void FieldAutocompleteInner::setSel(int sel, bool scroll) {
updateSelectedRow(); updateSelectedRow();
if (scroll && _sel >= 0) { if (scroll && _sel >= 0) {
if (_srows->isEmpty()) { if (_srows->empty()) {
emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight); emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight);
} else { } else {
int32 row = _sel / _stickersPerRow; int32 row = _sel / _stickersPerRow;
@ -866,7 +867,7 @@ void FieldAutocompleteInner::onUpdateSelected(bool force) {
if (_down >= 0 && !_previewShown) return; if (_down >= 0 && !_previewShown) return;
int32 sel = -1, maxSel = 0; int32 sel = -1, maxSel = 0;
if (!_srows->isEmpty()) { if (!_srows->empty()) {
int32 rows = rowscount(_srows->size(), _stickersPerRow); int32 rows = rowscount(_srows->size(), _stickersPerRow);
int32 row = (mouse.y() >= st::stickerPanPadding) ? ((mouse.y() - st::stickerPanPadding) / st::stickerPanSize.height()) : -1; 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; int32 col = (mouse.x() >= st::stickerPanPadding) ? ((mouse.x() - st::stickerPanPadding) / st::stickerPanSize.width()) : -1;

View File

@ -19,6 +19,7 @@ namespace internal {
using MentionRows = QList<UserData*>; using MentionRows = QList<UserData*>;
using HashtagRows = QList<QString>; using HashtagRows = QList<QString>;
using BotCommandRows = QList<QPair<UserData*, const BotCommand*>>; using BotCommandRows = QList<QPair<UserData*, const BotCommand*>>;
using StickerRows = std::vector<not_null<DocumentData*>>;
class FieldAutocompleteInner; class FieldAutocompleteInner;
@ -53,7 +54,7 @@ public:
bool chooseSelected(ChooseMethod method) const; bool chooseSelected(ChooseMethod method) const;
bool stickersShown() const { bool stickersShown() const {
return !_srows.isEmpty(); return !_srows.empty();
} }
bool overlaps(const QRect &globalRect) { bool overlaps(const QRect &globalRect) {
@ -92,9 +93,9 @@ private:
internal::MentionRows _mrows; internal::MentionRows _mrows;
internal::HashtagRows _hrows; internal::HashtagRows _hrows;
internal::BotCommandRows _brows; internal::BotCommandRows _brows;
Stickers::Pack _srows; internal::StickerRows _srows;
void rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const Stickers::Pack &srows, bool resetScroll); void rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const internal::StickerRows &srows, bool resetScroll);
object_ptr<Ui::ScrollArea> _scroll; object_ptr<Ui::ScrollArea> _scroll;
QPointer<internal::FieldAutocompleteInner> _inner; QPointer<internal::FieldAutocompleteInner> _inner;
@ -103,6 +104,7 @@ private:
UserData *_user = nullptr; UserData *_user = nullptr;
ChannelData *_channel = nullptr; ChannelData *_channel = nullptr;
EmojiPtr _emoji; EmojiPtr _emoji;
uint64 _stickersSeed = 0;
enum class Type { enum class Type {
Mentions, Mentions,
Hashtags, Hashtags,
@ -129,7 +131,7 @@ class FieldAutocompleteInner final : public TWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, Stickers::Pack *srows); FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerRows *srows);
void clearSel(bool hidden = false); void clearSel(bool hidden = false);
bool moveSel(int key); bool moveSel(int key);
@ -167,7 +169,7 @@ private:
MentionRows *_mrows; MentionRows *_mrows;
HashtagRows *_hrows; HashtagRows *_hrows;
BotCommandRows *_brows; BotCommandRows *_brows;
Stickers::Pack *_srows; StickerRows *_srows;
int32 _stickersPerRow, _recentInlineBotsInRows; int32 _stickersPerRow, _recentInlineBotsInRows;
int32 _sel, _down; int32 _sel, _down;
bool _mouseSel; bool _mouseSel;

View File

@ -668,19 +668,84 @@ void GifsReceived(const QVector<MTPDocument> &items, int32 hash) {
Auth().data().notifySavedGifsUpdated(); Auth().data().notifySavedGifsUpdated();
} }
Pack GetListByEmoji(not_null<EmojiPtr> emoji) { std::vector<not_null<DocumentData*>> GetListByEmoji(
auto original = emoji->original(); not_null<EmojiPtr> emoji,
auto result = Pack(); uint64 seed) {
auto setsToRequest = QMap<uint64, uint64>(); const auto original = emoji->original();
auto &sets = Auth().data().stickerSetsRef();
auto faved = Pack(); struct StickerWithDate {
auto favedIt = sets.find(Stickers::FavedSetId); not_null<DocumentData*> document;
if (favedIt != sets.cend()) { TimeId date = 0;
auto i = favedIt->emoji.constFind(original); };
if (i != favedIt->emoji.cend()) { auto result = std::vector<StickerWithDate>();
faved = *i; auto &sets = Auth().data().stickerSetsRef();
result = faved; auto setsToRequest = base::flat_map<uint64, uint64>();
const auto add = [&](not_null<DocumentData*> document, TimeId date) {
if (ranges::find(result, document, [](const StickerWithDate &data) {
return data.document;
}) == result.end()) {
result.push_back({ document, date });
}
};
constexpr auto kSlice = 65536;
const auto CreateSortKey = [&](
not_null<DocumentData*> document,
int base) {
return TimeId(base + int((document->id ^ seed) % kSlice));
};
const auto CreateRecentSortKey = [&](not_null<DocumentData*> document) {
return CreateSortKey(document, kSlice * 4);
};
auto myCounter = 0;
const auto CreateMySortKey = [&] {
return (kSlice * 4 - (++myCounter));
};
const auto CreateFeaturedSortKey = [&](not_null<DocumentData*> document) {
return CreateSortKey(document, kSlice * 2);
};
const auto CreateOtherSortKey = [&](not_null<DocumentData*> document) {
return CreateSortKey(document, kSlice);
};
const auto InstallDate = [&](not_null<DocumentData*> document) {
Expects(document->sticker() != nullptr);
const auto sticker = document->sticker();
if (sticker->set.type() == mtpc_inputStickerSetID) {
const auto setId = sticker->set.c_inputStickerSetID().vid.v;
const auto setIt = sets.find(setId);
if (setIt != sets.end()) {
return setIt->installDate;
}
}
return TimeId(0);
};
auto recentIt = sets.find(Stickers::CloudRecentSetId);
if (recentIt != sets.cend()) {
auto i = recentIt->emoji.constFind(original);
if (i != recentIt->emoji.cend()) {
result.reserve(i->size());
for (const auto document : *i) {
const auto usageDate = [&] {
if (recentIt->dates.empty()) {
return TimeId(0);
}
const auto index = recentIt->stickers.indexOf(document);
if (index < 0) {
return TimeId(0);
}
Assert(index < recentIt->dates.size());
return recentIt->dates[index];
}();
const auto date = usageDate
? usageDate
: InstallDate(document);
result.push_back({
document,
date ? date : CreateRecentSortKey(document) });
}
} }
} }
const auto addList = [&](const Order &order, MTPDstickerSet::Flag skip) { const auto addList = [&](const Order &order, MTPDstickerSet::Flag skip) {
@ -690,7 +755,7 @@ Pack GetListByEmoji(not_null<EmojiPtr> emoji) {
continue; continue;
} }
if (it->emoji.isEmpty()) { if (it->emoji.isEmpty()) {
setsToRequest.insert(it->id, it->access); setsToRequest.emplace(it->id, it->access);
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
continue; continue;
} }
@ -698,11 +763,16 @@ Pack GetListByEmoji(not_null<EmojiPtr> emoji) {
if (i == it->emoji.cend()) { if (i == it->emoji.cend()) {
continue; continue;
} }
const auto my = (it->flags & MTPDstickerSet::Flag::f_installed_date);
result.reserve(result.size() + i->size()); result.reserve(result.size() + i->size());
for_const (const auto document, *i) { for (const auto document : *i) {
if (!faved.contains(document)) { const auto installDate = my ? it->installDate : TimeId(0);
result.push_back(document); const auto date = (installDate > 1)
} ? installDate
: my
? CreateMySortKey()
: CreateFeaturedSortKey(document);
add(document, date);
} }
} }
}; };
@ -714,21 +784,32 @@ Pack GetListByEmoji(not_null<EmojiPtr> emoji) {
Auth().data().featuredStickerSetsOrder(), Auth().data().featuredStickerSetsOrder(),
MTPDstickerSet::Flag::f_installed_date); MTPDstickerSet::Flag::f_installed_date);
if (!setsToRequest.isEmpty()) { if (!setsToRequest.empty()) {
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { for (const auto [setId, accessHash] : setsToRequest) {
Auth().api().scheduleStickerSetRequest(i.key(), i.value()); Auth().api().scheduleStickerSetRequest(setId, accessHash);
} }
Auth().api().requestStickerSets(); Auth().api().requestStickerSets();
} }
if (const auto pack = Auth().api().stickersByEmoji(original)) {
for (const auto document : *pack) { const auto others = Auth().api().stickersByEmoji(original);
if (!base::contains(result, document)) { if (!others) {
result.push_back(document); return {};
}
}
return result;
} }
return Pack(); result.reserve(result.size() + others->size());
for (const auto document : *others) {
add(document, CreateOtherSortKey(document));
}
ranges::action::sort(
result,
std::greater<>(),
[](const StickerWithDate &data) { return data.date; });
return ranges::view::all(
result
) | ranges::view::transform([](const StickerWithDate &data) {
return data.document;
}) | ranges::to_vector;
} }
base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet( base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(

View File

@ -86,7 +86,9 @@ void FeaturedSetsReceived(
int32 hash); int32 hash);
void GifsReceived(const QVector<MTPDocument> &items, int32 hash); void GifsReceived(const QVector<MTPDocument> &items, int32 hash);
Pack GetListByEmoji(not_null<EmojiPtr> emoji); std::vector<not_null<DocumentData*>> GetListByEmoji(
not_null<EmojiPtr> emoji,
uint64 seed);
base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet( base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(
not_null<DocumentData*> document); not_null<DocumentData*> document);

View File

@ -4058,19 +4058,45 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
it->title = lang(lng_recent_stickers); it->title = lang(lng_recent_stickers);
} }
} }
auto removedFromEmoji = std::vector<not_null<EmojiPtr>>();
auto index = it->stickers.indexOf(sticker); auto index = it->stickers.indexOf(sticker);
if (index > 0) { if (index > 0) {
if (!it->dates.empty()) { if (it->dates.empty()) {
Auth().api().requestRecentStickersForce();
} else {
Assert(it->dates.size() == it->stickers.size()); Assert(it->dates.size() == it->stickers.size());
it->dates.erase(it->dates.begin() + index); it->dates.erase(it->dates.begin() + index);
} }
it->stickers.removeAt(index); it->stickers.removeAt(index);
for (auto i = it->emoji.begin(); i != it->emoji.end();) {
if (const auto index = i->indexOf(sticker); index >= 0) {
removedFromEmoji.push_back(i.key());
i->removeAt(index);
if (i->isEmpty()) {
i = it->emoji.erase(i);
continue;
}
}
++i;
}
} }
if (index) { if (index) {
if (it->dates.size() == it->stickers.size()) { if (it->dates.size() == it->stickers.size()) {
it->dates.insert(it->dates.begin(), unixtime()); it->dates.insert(it->dates.begin(), unixtime());
} }
it->stickers.push_front(sticker); it->stickers.push_front(sticker);
if (const auto emojiList = Stickers::GetEmojiListFromSet(sticker)) {
for (const auto emoji : *emojiList) {
it->emoji[emoji].push_front(sticker);
}
} else if (!removedFromEmoji.empty()) {
for (const auto emoji : removedFromEmoji) {
it->emoji[emoji].push_front(sticker);
}
} else {
Auth().api().requestRecentStickersForce();
}
writeRecentStickers = true; writeRecentStickers = true;
} }