Suggest faved stickers by emoji.

Request added faved sticker emoji if its pack is not loaded yet.
This commit is contained in:
John Preston 2017-08-03 13:15:57 +02:00
parent 8188724920
commit d44b303fb3
6 changed files with 207 additions and 85 deletions

View file

@ -1301,9 +1301,9 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
custom = sets.end();
}
bool writeRecent = false;
RecentStickerPack &recent(cGetRecentStickers());
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
auto writeRecent = false;
auto &recent = cGetRecentStickers();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
i = recent.erase(i);
writeRecent = true;
@ -1612,7 +1612,7 @@ void ApiWrap::requestFavedStickers(TimeId now) {
case mtpc_messages_favedStickersNotModified: return;
case mtpc_messages_favedStickers: {
auto &d = result.c_messages_favedStickers();
Stickers::SpecialSetReceived(Stickers::FavedSetId, lang(lng_faved_stickers), d.vstickers.v, d.vhash.v);
Stickers::SpecialSetReceived(Stickers::FavedSetId, lang(lng_faved_stickers), d.vstickers.v, d.vhash.v, d.vpacks.v);
} return;
default: Unexpected("Type in ApiWrap::favedStickersDone()");
}

View file

@ -28,6 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_widgets.h"
#include "styles/style_chat_helpers.h"
#include "auth_session.h"
#include "chat_helpers/stickers.h"
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
, _scroll(this, st::mentionScroll) {
@ -147,30 +148,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
internal::BotCommandRows brows;
StickerPack srows;
if (_emoji) {
auto original = _emoji->original();
QMap<uint64, uint64> setsToRequest;
auto &sets = Global::RefStickerSets();
auto &order = Global::StickerSetsOrder();
for (auto i = 0, l = order.size(); i != l; ++i) {
auto it = sets.find(order[i]);
if (it != sets.cend()) {
if (it->emoji.isEmpty()) {
setsToRequest.insert(it->id, it->access);
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
} else if (!(it->flags & MTPDstickerSet::Flag::f_archived)) {
auto i = it->emoji.constFind(original);
if (i != it->emoji.cend()) {
srows += *i;
}
}
}
}
if (!setsToRequest.isEmpty() && App::api()) {
for (QMap<uint64, uint64>::const_iterator i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
App::api()->scheduleStickerSetRequest(i.key(), i.value());
}
App::api()->requestStickerSets();
}
srows = Stickers::GetListByEmoji(_emoji);
} else if (_type == Type::Mentions) {
int maxListSize = _addInlineBots ? cRecentInlineBots().size() : 0;
if (_chat) {

View file

@ -183,43 +183,115 @@ void MarkFeaturedAsRead(uint64 setId) {
FeaturedReaderInstance->scheduleRead(setId);
}
bool IsFaved(DocumentData *document) {
bool IsFaved(gsl::not_null<DocumentData*> document) {
auto it = Global::StickerSets().constFind(FavedSetId);
return (it != Global::StickerSets().cend()) && it->stickers.contains(document);
}
void SetFaved(DocumentData *document, bool faved) {
void SetIsFaved(gsl::not_null<DocumentData*> document, const std::vector<gsl::not_null<EmojiPtr>> *emojiList = nullptr) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(FavedSetId);
if (faved) {
if (it == sets.end()) {
it = sets.insert(FavedSetId, Set(FavedSetId, 0, lang(lng_faved_stickers), QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special)));
if (it == sets.end()) {
it = sets.insert(FavedSetId, Set(FavedSetId, 0, lang(lng_faved_stickers), QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special)));
}
auto index = it->stickers.indexOf(document);
if (index == 0) {
return;
}
if (index > 0) {
// Push this sticker to the front.
while (index-- != 0) {
it->stickers[index + 1] = it->stickers[index];
}
auto index = it->stickers.indexOf(document);
if (index != 0) {
it->stickers[0] = document;
for (auto &list : it->emoji) {
auto index = list.indexOf(document);
if (index > 0) {
// Push this sticker to the front.
while (index-- != 0) {
it->stickers[index + 1] = it->stickers[index];
list[index + 1] = list[index];
}
it->stickers[0] = document;
} else {
it->stickers.push_front(document);
list[0] = document;
}
Local::writeFavedStickers();
emit App::main()->stickersUpdated();
App::main()->onStickersInstalled(FavedSetId);
}
} else if (it != sets.end()) {
auto index = it->stickers.indexOf(document);
} else if (emojiList) {
it->stickers.push_front(document);
for (auto emoji : *emojiList) {
it->emoji[emoji].push_front(document);
}
} else {
auto list = GetEmojiListFromSet(document);
if (list.empty()) {
MTP::send(MTPmessages_GetStickerSet(document->sticker()->set), rpcDone([document](const MTPmessages_StickerSet &result) {
Expects(result.type() == mtpc_messages_stickerSet);
auto list = std::vector<gsl::not_null<EmojiPtr>>();
auto &d = result.c_messages_stickerSet();
list.reserve(d.vpacks.v.size());
for_const (auto &mtpPack, d.vpacks.v) {
auto &pack = mtpPack.c_stickerPack();
for_const (auto &documentId, pack.vdocuments.v) {
if (documentId.v == document->id) {
if (auto emoji = Ui::Emoji::Find(qs(mtpPack.c_stickerPack().vemoticon))) {
list.push_back(emoji);
}
break;
}
}
}
if (list.empty()) {
if (auto sticker = document->sticker()) {
if (auto emoji = Ui::Emoji::Find(sticker->alt)) {
list.push_back(emoji);
}
}
}
SetIsFaved(document, &list);
}));
return;
}
it->stickers.push_front(document);
for (auto emoji : list) {
it->emoji[emoji].push_front(document);
}
}
Local::writeFavedStickers();
emit App::main()->stickersUpdated();
App::main()->onStickersInstalled(FavedSetId);
}
void SetIsNotFaved(gsl::not_null<DocumentData*> document) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(FavedSetId);
if (it == sets.end()) {
return;
}
auto index = it->stickers.indexOf(document);
if (index < 0) {
return;
}
it->stickers.removeAt(index);
for (auto i = it->emoji.begin(); i != it->emoji.end();) {
auto index = i->indexOf(document);
if (index >= 0) {
it->stickers.removeAt(index);
if (it->stickers.empty()) {
sets.erase(it);
i->removeAt(index);
if (i->empty()) {
i = it->emoji.erase(i);
continue;
}
Local::writeFavedStickers();
emit App::main()->stickersUpdated();
}
++i;
}
if (it->stickers.empty()) {
sets.erase(it);
}
Local::writeFavedStickers();
emit App::main()->stickersUpdated();
}
void SetFaved(gsl::not_null<DocumentData*> document, bool faved) {
if (faved) {
SetIsFaved(document);
} else {
SetIsNotFaved(document);
}
}
@ -287,7 +359,30 @@ void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash) {
if (App::main()) emit App::main()->stickersUpdated();
}
void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTPDocument> &items, int32 hash) {
void SetPackAndEmoji(Set &set, StickerPack &&pack, const QVector<MTPStickerPack> &packs) {
set.stickers = std::move(pack);
set.emoji.clear();
for_const (auto &mtpPack, packs) {
t_assert(mtpPack.type() == mtpc_stickerPack);
auto &pack = mtpPack.c_stickerPack();
if (auto emoji = Ui::Emoji::Find(qs(pack.vemoticon))) {
emoji = emoji->original();
auto &stickers = pack.vdocuments.v;
auto p = StickerPack();
p.reserve(stickers.size());
for (auto j = 0, c = stickers.size(); j != c; ++j) {
auto document = App::document(stickers[j].v);
if (!document || !document->sticker()) continue;
p.push_back(document);
}
set.emoji.insert(emoji, p);
}
}
}
void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTPDocument> &items, int32 hash, const QVector<MTPStickerPack> &packs) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
@ -338,8 +433,7 @@ void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTP
if (pack.isEmpty()) {
sets.erase(it);
} else {
it->stickers = pack;
it->emoji.clear();
SetPackAndEmoji(*it, std::move(pack), packs);
}
if (writeRecent) {
@ -492,6 +586,71 @@ void GifsReceived(const QVector<MTPDocument> &items, int32 hash) {
AuthSession::Current().data().savedGifsUpdated().notify();
}
StickerPack GetListByEmoji(gsl::not_null<EmojiPtr> emoji) {
auto original = emoji->original();
auto result = StickerPack();
auto setsToRequest = QMap<uint64, uint64>();
auto &sets = Global::RefStickerSets();
auto faved = StickerPack();
auto favedIt = sets.find(Stickers::FavedSetId);
if (favedIt != sets.cend()) {
auto i = favedIt->emoji.constFind(original);
if (i != favedIt->emoji.cend()) {
faved = *i;
result = faved;
}
}
auto &order = Global::StickerSetsOrder();
for (auto i = 0, l = order.size(); i != l; ++i) {
auto it = sets.find(order[i]);
if (it != sets.cend()) {
if (it->emoji.isEmpty()) {
setsToRequest.insert(it->id, it->access);
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
} else if (!(it->flags & MTPDstickerSet::Flag::f_archived)) {
auto i = it->emoji.constFind(original);
if (i != it->emoji.cend()) {
result.reserve(result.size() + i->size());
for_const (auto sticker, *i) {
if (!faved.contains(sticker)) {
result.push_back(sticker);
}
}
}
}
}
}
if (!setsToRequest.isEmpty()) {
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
AuthSession::Current().api().scheduleStickerSetRequest(i.key(), i.value());
}
AuthSession::Current().api().requestStickerSets();
}
return result;
}
std::vector<gsl::not_null<EmojiPtr>> GetEmojiListFromSet(gsl::not_null<DocumentData*> document) {
auto result = std::vector<gsl::not_null<EmojiPtr>>();
if (auto sticker = document->sticker()) {
auto &inputSet = sticker->set;
if (inputSet.type() != mtpc_inputStickerSetID) {
return result;
}
auto &sets = Global::StickerSets();
auto it = sets.constFind(inputSet.c_inputStickerSetID().vid.v);
if (it == sets.cend()) {
return result;
}
for (auto i = it->emoji.cbegin(), e = it->emoji.cend(); i != e; ++i) {
if (i->contains(document)) {
result.push_back(i.key());
}
}
}
return result;
}
namespace internal {
FeaturedReader::FeaturedReader(QObject *parent) : QObject(parent)

View file

@ -31,14 +31,17 @@ bool ApplyArchivedResultFake(); // For testing.
void InstallLocally(uint64 setId);
void UndoInstallLocally(uint64 setId);
void MarkFeaturedAsRead(uint64 setId);
bool IsFaved(DocumentData *document);
void SetFaved(DocumentData *document, bool faved);
bool IsFaved(gsl::not_null<DocumentData*> document);
void SetFaved(gsl::not_null<DocumentData*> document, bool faved);
void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash);
void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTPDocument> &items, int32 hash);
void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTPDocument> &items, int32 hash, const QVector<MTPStickerPack> &packs = QVector<MTPStickerPack>());
void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVector<MTPlong> &unread, int32 hash);
void GifsReceived(const QVector<MTPDocument> &items, int32 hash);
StickerPack GetListByEmoji(gsl::not_null<EmojiPtr> emoji);
std::vector<gsl::not_null<EmojiPtr>> GetEmojiListFromSet(gsl::not_null<DocumentData*> document);
namespace internal {
class FeaturedReader : public QObject, private MTP::Sender {

View file

@ -33,6 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/shadow.h"
#include "window/window_main_menu.h"
#include "auth_session.h"
#include "chat_helpers/stickers.h"
#include "window/window_controller.h"
namespace {
@ -756,12 +757,12 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
}
p.fillRect(r, st::stickerPreviewBg);
p.drawPixmap((width() - w) / 2, (height() - h) / 2, image);
if (!_emojiList.isEmpty()) {
if (!_emojiList.empty()) {
auto emojiCount = _emojiList.size();
auto emojiWidth = (emojiCount * _emojiSize) + (emojiCount - 1) * st::stickerEmojiSkip;
auto emojiLeft = (width() - emojiWidth) / 2;
auto esize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
for_const (auto emoji, _emojiList) {
for (auto emoji : _emojiList) {
p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - (_emojiSize * 2), width(), App::emojiLarge(), QRect(emoji->x() * esize, emoji->y() * esize, esize, esize));
emojiLeft += _emojiSize + st::stickerEmojiSkip;
}
@ -825,36 +826,17 @@ void MediaPreviewWidget::hidePreview() {
}
void MediaPreviewWidget::fillEmojiString() {
auto getStickerEmojiList = [this](uint64 setId) {
QList<EmojiPtr> result;
auto &sets = Global::StickerSets();
auto it = sets.constFind(setId);
if (it == sets.cend()) {
return result;
}
for (auto i = it->emoji.cbegin(), e = it->emoji.cend(); i != e; ++i) {
for_const (auto document, *i) {
if (document == _document) {
result.append(i.key());
if (result.size() >= kStickerPreviewEmojiLimit) {
return result;
}
}
}
}
return result;
};
if (_photo) {
_emojiList.clear();
} else if (auto sticker = _document->sticker()) {
auto &inputSet = sticker->set;
if (inputSet.type() == mtpc_inputStickerSetID) {
_emojiList = getStickerEmojiList(inputSet.c_inputStickerSetID().vid.v);
} else {
_emojiList.clear();
_emojiList = Stickers::GetEmojiListFromSet(_document);
if (_emojiList.empty()) {
if (auto emoji = Ui::Emoji::Find(sticker->alt)) {
_emojiList.append(emoji);
_emojiList.push_back(emoji);
}
} else {
while (_emojiList.size() > kStickerPreviewEmojiLimit) {
_emojiList.pop_back();
}
}
} else {

View file

@ -197,7 +197,7 @@ private:
Media::Clip::ReaderPointer _gif;
int _emojiSize;
QList<EmojiPtr> _emojiList;
std::vector<gsl::not_null<EmojiPtr>> _emojiList;
void clipCallback(Media::Clip::Notification notification);