Save and load sticker set thumbnails.

This commit is contained in:
John Preston 2019-03-22 13:13:39 +04:00
parent eb1825defd
commit 386600baf9
6 changed files with 287 additions and 282 deletions

View File

@ -84,6 +84,7 @@ private:
int32 _setHash = 0;
MTPDstickerSet::Flags _setFlags = 0;
TimeId _setInstallDate = TimeId(0);
ImagePtr _setThumbnail;
MTPInputStickerSet _input;
@ -195,9 +196,8 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_packOvers.clear();
_selected = -1;
setCursor(style::cur_default);
if (set.type() == mtpc_messages_stickerSet) {
auto &d = set.c_messages_stickerSet();
auto &v = d.vdocuments.v;
set.match([&](const MTPDmessages_stickerSet &data) {
const auto &v = data.vdocuments.v;
_pack.reserve(v.size());
_packOvers.reserve(v.size());
for (const auto &item : v) {
@ -205,51 +205,58 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
if (!document->sticker()) continue;
_pack.push_back(document);
_packOvers.push_back(Animation());
_packOvers.emplace_back();
}
auto &packs = d.vpacks.v;
for (auto i = 0, l = packs.size(); i != l; ++i) {
if (packs.at(i).type() != mtpc_stickerPack) continue;
auto &pack = packs.at(i).c_stickerPack();
if (auto emoji = Ui::Emoji::Find(qs(pack.vemoticon))) {
emoji = emoji->original();
auto &stickers = pack.vdocuments.v;
for (const auto &pack : data.vpacks.v) {
pack.match([&](const MTPDstickerPack &pack) {
if (const auto emoji = Ui::Emoji::Find(qs(pack.vemoticon))) {
const auto original = emoji->original();
auto &stickers = pack.vdocuments.v;
Stickers::Pack p;
p.reserve(stickers.size());
for (auto j = 0, c = stickers.size(); j != c; ++j) {
auto doc = Auth().data().document(stickers[j].v);
if (!doc || !doc->sticker()) continue;
auto p = Stickers::Pack();
p.reserve(stickers.size());
for (auto j = 0, c = stickers.size(); j != c; ++j) {
auto doc = Auth().data().document(stickers[j].v);
if (!doc || !doc->sticker()) continue;
p.push_back(doc);
p.push_back(doc);
}
_emoji.insert(original, p);
}
_emoji.insert(emoji, p);
}
});
}
if (d.vset.type() == mtpc_stickerSet) {
auto &s = d.vset.c_stickerSet();
_setTitle = Stickers::GetSetTitle(s);
_setShortName = qs(s.vshort_name);
_setId = s.vid.v;
_setAccess = s.vaccess_hash.v;
_setCount = s.vcount.v;
_setHash = s.vhash.v;
_setFlags = s.vflags.v;
_setInstallDate = s.has_installed_date()
? s.vinstalled_date.v
data.vset.match([&](const MTPDstickerSet & set) {
_setTitle = Stickers::GetSetTitle(set);
_setShortName = qs(set.vshort_name);
_setId = set.vid.v;
_setAccess = set.vaccess_hash.v;
_setCount = set.vcount.v;
_setHash = set.vhash.v;
_setFlags = set.vflags.v;
_setInstallDate = set.has_installed_date()
? set.vinstalled_date.v
: TimeId(0);
_setThumbnail = set.has_thumb()
? App::image(set.vthumb)
: ImagePtr();
auto &sets = Auth().data().stickerSetsRef();
auto it = sets.find(_setId);
const auto it = sets.find(_setId);
if (it != sets.cend()) {
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_special);
using ClientFlag = MTPDstickerSet_ClientFlag;
const auto clientFlags = it->flags
& (ClientFlag::f_featured
| ClientFlag::f_not_loaded
| ClientFlag::f_unread
| ClientFlag::f_special);
_setFlags |= clientFlags;
it->flags = _setFlags;
it->installDate = _setInstallDate;
it->stickers = _pack;
it->emoji = _emoji;
it->thumbnail = _setThumbnail;
}
}
}
});
});
if (_pack.isEmpty()) {
Ui::show(Box<InformBox>(lang(lng_stickers_not_found)));
@ -307,7 +314,8 @@ void StickerSetBox::Inner::installDone(const MTPmessages_StickerSetInstallResult
_setCount,
_setHash,
_setFlags,
_setInstallDate));
_setInstallDate,
_setThumbnail));
} else {
it->flags = _setFlags;
it->installDate = _setInstallDate;

View File

@ -253,7 +253,8 @@ void SetIsFaved(not_null<DocumentData*> document, std::optional<std::vector<not_
0, // count
0, // hash
MTPDstickerSet_ClientFlag::f_special | 0,
TimeId(0)));
TimeId(0),
ImagePtr()));
}
auto index = it->stickers.indexOf(document);
if (index == 0) {
@ -467,7 +468,8 @@ void SpecialSetReceived(
0, // count
0, // hash
MTPDstickerSet_ClientFlag::f_special | 0,
TimeId(0)));
TimeId(0),
ImagePtr()));
} else {
it->title = setTitle;
}
@ -545,19 +547,28 @@ void SpecialSetReceived(
Auth().data().notifyStickersUpdated();
}
void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVector<MTPlong> &unread, int32 hash) {
OrderedSet<uint64> unreadMap;
for_const (auto &unreadSetId, unread) {
unreadMap.insert(unreadSetId.v);
}
void FeaturedSetsReceived(
const QVector<MTPStickerSetCovered> &data,
const QVector<MTPlong> &unread,
int32 hash) {
auto &&unreadIds = ranges::view::all(
unread
) | ranges::view::transform([](const MTPlong &id) {
return id.v;
});
const auto unreadMap = base::flat_set<uint64>{
unreadIds.begin(),
unreadIds.end()
};
auto &setsOrder = Auth().data().featuredStickerSetsOrderRef();
setsOrder.clear();
auto &sets = Auth().data().stickerSetsRef();
QMap<uint64, uint64> setsToRequest;
auto setsToRequest = base::flat_map<uint64, uint64>();
for (auto &set : sets) {
set.flags &= ~MTPDstickerSet_ClientFlag::f_featured; // mark for removing
// Mark for removing.
set.flags &= ~MTPDstickerSet_ClientFlag::f_featured;
}
for (int i = 0, l = data.size(); i != l; ++i) {
auto &setData = data[i];
@ -583,6 +594,9 @@ void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVect
const auto installDate = set->has_installed_date()
? set->vinstalled_date.v
: TimeId(0);
const auto thumbnail = set->has_thumb()
? App::image(set->vthumb)
: ImagePtr();
if (it == sets.cend()) {
auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured
| MTPDstickerSet_ClientFlag::f_not_loaded;
@ -597,7 +611,8 @@ void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVect
set->vcount.v,
set->vhash.v,
set->vflags.v | setClientFlags,
installDate));
installDate,
thumbnail));
} else {
it->access = set->vaccess_hash.v;
it->title = title;
@ -606,6 +621,7 @@ void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVect
it->flags = set->vflags.v | clientFlags;
it->flags |= MTPDstickerSet_ClientFlag::f_featured;
it->installDate = installDate;
it->thumbnail = thumbnail;
if (unreadMap.contains(it->id)) {
it->flags |= MTPDstickerSet_ClientFlag::f_unread;
} else {
@ -619,7 +635,7 @@ void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVect
}
setsOrder.push_back(set->vid.v);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.insert(set->vid.v, set->vaccess_hash.v);
setsToRequest.emplace(set->vid.v, set->vaccess_hash.v);
}
}
}
@ -645,10 +661,10 @@ void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVect
LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(hash).arg(Local::countFeaturedStickersHash()));
}
if (!setsToRequest.isEmpty()) {
if (!setsToRequest.empty()) {
auto &api = Auth().api();
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
api.scheduleStickerSetRequest(i.key(), i.value());
for (const auto [setId, accessHash] : setsToRequest) {
api.scheduleStickerSetRequest(setId, accessHash);
}
api.requestStickerSets();
}
@ -843,7 +859,7 @@ std::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(
auto result = std::vector<not_null<EmojiPtr>>();
for (auto i = it->emoji.cbegin(), e = it->emoji.cend(); i != e; ++i) {
if (i->contains(document)) {
result.push_back(i.key());
result.emplace_back(i.key());
}
}
if (result.empty()) {
@ -868,7 +884,8 @@ Set *FeedSet(const MTPDstickerSet &set) {
set.vcount.v,
set.vhash.v,
set.vflags.v | MTPDstickerSet_ClientFlag::f_not_loaded,
set.has_installed_date() ? set.vinstalled_date.v : TimeId(0)));
set.has_installed_date() ? set.vinstalled_date.v : TimeId(0),
set.has_thumb() ? App::image(set.vthumb) : ImagePtr()));
} else {
it->access = set.vaccess_hash.v;
it->title = title;
@ -881,8 +898,11 @@ Set *FeedSet(const MTPDstickerSet &set) {
| MTPDstickerSet_ClientFlag::f_special);
it->flags = set.vflags.v | clientFlags;
it->installDate = set.has_installed_date()
? set.vinstalled_date.v
? (set.vinstalled_date.v ? set.vinstalled_date.v : unixtime())
: TimeId(0);
it->thumbnail = set.has_thumb()
? App::image(set.vthumb)
: ImagePtr();
if (it->count != set.vcount.v
|| it->hash != set.vhash.v
|| it->emoji.isEmpty()) {
@ -908,14 +928,23 @@ Set *FeedSet(const MTPDstickerSet &set) {
Set *FeedSetFull(const MTPmessages_StickerSet &data) {
Expects(data.type() == mtpc_messages_stickerSet);
Expects(data.c_messages_stickerSet().vset.type() == mtpc_stickerSet);
auto &d = data.c_messages_stickerSet();
auto set = FeedSet(d.vset.c_stickerSet());
const auto &d = data.c_messages_stickerSet();
const auto &s = d.vset.c_stickerSet();
auto &sets = Auth().data().stickerSetsRef();
auto it = sets.find(s.vid.v);
const auto wasArchived = (it->flags & MTPDstickerSet::Flag::f_archived);
auto set = FeedSet(s);
set->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded;
auto &sets = Auth().data().stickerSetsRef();
auto &d_docs = d.vdocuments.v;
auto custom = sets.find(Stickers::CustomSetId);
auto inputSet = MTP_inputStickerSetID(
MTP_long(set->id),
MTP_long(set->access));
auto pack = Pack();
pack.reserve(d_docs.size());
@ -924,6 +953,9 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) {
if (!document->sticker()) continue;
pack.push_back(document);
if (document->sticker()->set.type() != mtpc_inputStickerSetID) {
document->sticker()->set = inputSet;
}
if (custom != sets.cend()) {
const auto index = custom->stickers.indexOf(document);
if (index >= 0) {
@ -982,14 +1014,18 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) {
}
if (set) {
const auto isArchived = (set->flags & MTPDstickerSet::Flag::f_archived);
if (set->flags & MTPDstickerSet::Flag::f_installed_date) {
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
if (!isArchived) {
Local::writeInstalledStickers();
}
}
if (set->flags & MTPDstickerSet_ClientFlag::f_featured) {
Local::writeFeaturedStickers();
}
if (wasArchived != isArchived) {
Local::writeArchivedStickers();
}
}
Auth().data().notifyStickersUpdated();
@ -997,6 +1033,33 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) {
return set;
}
void NewSetReceived(const MTPmessages_StickerSet &data) {
bool writeArchived = false;
const auto &set = data.c_messages_stickerSet();
const auto &s = set.vset.c_stickerSet();
if (!s.has_installed_date()) {
LOG(("API Error: "
"updateNewStickerSet without install_date flag."));
return;
} else if (s.is_archived()) {
LOG(("API Error: "
"updateNewStickerSet with archived flag."));
return;
} else if (s.is_masks()) {
return;
}
auto &order = Auth().data().stickerSetsOrderRef();
int32 insertAtIndex = 0, currentIndex = order.indexOf(s.vid.v);
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
order.removeAt(currentIndex);
}
order.insert(insertAtIndex, s.vid.v);
}
FeedSetFull(data);
}
QString GetSetTitle(const MTPDstickerSet &s) {
auto title = qs(s.vtitle);
if ((s.vflags.v & MTPDstickerSet::Flag::f_official) && !title.compare(qstr("Great Minds"), Qt::CaseInsensitive)) {

View File

@ -34,7 +34,8 @@ struct Set {
int count,
int32 hash,
MTPDstickerSet::Flags flags,
TimeId installDate)
TimeId installDate,
ImagePtr thumbnail)
: id(id)
, access(access)
, title(title)
@ -42,7 +43,8 @@ struct Set {
, count(count)
, hash(hash)
, flags(flags)
, installDate(installDate) {
, installDate(installDate)
, thumbnail(thumbnail) {
}
uint64 id = 0;
uint64 access = 0;
@ -51,6 +53,7 @@ struct Set {
int32 hash = 0;
MTPDstickerSet::Flags flags;
TimeId installDate = 0;
ImagePtr thumbnail;
Pack stickers;
std::vector<TimeId> dates;
Pack covers;
@ -94,6 +97,7 @@ std::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(
Set *FeedSet(const MTPDstickerSet &data);
Set *FeedSetFull(const MTPmessages_StickerSet &data);
void NewSetReceived(const MTPmessages_StickerSet &data);
QString GetSetTitle(const MTPDstickerSet &s);

View File

@ -3382,7 +3382,8 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
0, // count
0, // hash
MTPDstickerSet_ClientFlag::f_special | 0,
TimeId(0)));
TimeId(0),
ImagePtr()));
} else {
it->title = lang(lng_recent_stickers);
}
@ -4435,99 +4436,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
////// Cloud sticker sets
case mtpc_updateNewStickerSet: {
auto &d = update.c_updateNewStickerSet();
bool writeArchived = false;
if (d.vstickerset.type() == mtpc_messages_stickerSet) {
auto &set = d.vstickerset.c_messages_stickerSet();
if (set.vset.type() == mtpc_stickerSet) {
auto &s = set.vset.c_stickerSet();
if (!s.has_installed_date()) {
LOG(("API Error: "
"updateNewStickerSet without install_date flag."));
}
if (!s.is_masks()) {
auto &sets = session().data().stickerSetsRef();
auto it = sets.find(s.vid.v);
if (it == sets.cend()) {
it = sets.insert(s.vid.v, Stickers::Set(
s.vid.v,
s.vaccess_hash.v,
Stickers::GetSetTitle(s),
qs(s.vshort_name),
s.vcount.v,
s.vhash.v,
s.vflags.v | MTPDstickerSet::Flag::f_installed_date,
s.has_installed_date() ? s.vinstalled_date.v : unixtime()));
} else {
it->flags |= MTPDstickerSet::Flag::f_installed_date;
if (!it->installDate) {
it->installDate = unixtime();
}
if (it->flags & MTPDstickerSet::Flag::f_archived) {
it->flags &= ~MTPDstickerSet::Flag::f_archived;
writeArchived = true;
}
}
auto inputSet = MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access));
auto &v = set.vdocuments.v;
it->stickers.clear();
it->stickers.reserve(v.size());
for (const auto &item : v) {
const auto document = session().data().processDocument(
item);
if (!document->sticker()) continue;
it->stickers.push_back(document);
if (document->sticker()->set.type() != mtpc_inputStickerSetID) {
document->sticker()->set = inputSet;
}
}
it->emoji.clear();
auto &packs = set.vpacks.v;
for (auto i = 0, l = packs.size(); i != l; ++i) {
if (packs[i].type() != mtpc_stickerPack) continue;
auto &pack = packs.at(i).c_stickerPack();
if (auto emoji = Ui::Emoji::Find(qs(pack.vemoticon))) {
emoji = emoji->original();
auto &stickers = pack.vdocuments.v;
Stickers::Pack p;
p.reserve(stickers.size());
for (auto j = 0, c = stickers.size(); j != c; ++j) {
auto doc = session().data().document(stickers[j].v);
if (!doc->sticker()) continue;
p.push_back(doc);
}
it->emoji.insert(emoji, p);
}
}
auto &order = session().data().stickerSetsOrderRef();
int32 insertAtIndex = 0, currentIndex = order.indexOf(s.vid.v);
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
order.removeAt(currentIndex);
}
order.insert(insertAtIndex, s.vid.v);
}
auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) {
for (int32 i = 0, l = it->stickers.size(); i < l; ++i) {
int32 removeIndex = custom->stickers.indexOf(it->stickers.at(i));
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
}
if (custom->stickers.isEmpty()) {
sets.erase(custom);
}
}
Local::writeInstalledStickers();
if (writeArchived) Local::writeArchivedStickers();
session().data().notifyStickersUpdated();
}
}
}
const auto &d = update.c_updateNewStickerSet();
Stickers::NewSetReceived(d.vstickerset);
} break;
case mtpc_updateStickerSetsOrder: {

View File

@ -95,9 +95,6 @@ enum class MTPDreplyKeyboardMarkup_ClientFlag : uint32 {
DEFINE_MTP_CLIENT_FLAGS(MTPDreplyKeyboardMarkup)
enum class MTPDstickerSet_ClientFlag : uint32 {
// old value for sticker set is not yet loaded flag
f_not_loaded__old = (1U << 31),
// sticker set is not yet loaded
f_not_loaded = (1U << 30),

View File

@ -60,6 +60,10 @@ constexpr auto kSinglePeerTypeChannel = qint32(3);
constexpr auto kSinglePeerTypeSelf = qint32(4);
constexpr auto kSinglePeerTypeEmpty = qint32(0);
constexpr auto kStickersVersionTag = quint32(-1);
constexpr auto kStickersSerializeVersion = 1;
constexpr auto kMaxSavedStickerSetsCount = 1000;
using Database = Storage::Cache::Database;
using FileKey = quint64;
@ -3339,55 +3343,43 @@ void cancelTask(TaskId id) {
}
void _writeStickerSet(QDataStream &stream, const Stickers::Set &set) {
bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded);
if (notLoaded) {
const auto writeInfo = [&](int count) {
stream
<< quint64(set.id)
<< quint64(set.access)
<< set.title
<< set.shortName
<< qint32(-set.count)
<< qint32(count)
<< qint32(set.hash)
<< qint32(set.flags);
if (AppVersion > 1002008) {
stream << qint32(set.installDate);
}
<< qint32(set.flags)
<< qint32(set.installDate);
Serialize::writeStorageImageLocation(
stream,
set.thumbnail ? set.thumbnail->location() : StorageImageLocation());
};
if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
writeInfo(-set.count);
return;
} else if (set.stickers.isEmpty()) {
return;
} else {
if (set.stickers.isEmpty()) return;
}
stream
<< quint64(set.id)
<< quint64(set.access)
<< set.title
<< set.shortName
<< qint32(set.stickers.size())
<< qint32(set.hash)
<< qint32(set.flags);
if (AppVersion > 1002008) {
stream << qint32(set.installDate);
writeInfo(set.stickers.size());
for (const auto &sticker : set.stickers) {
Serialize::Document::writeToStream(stream, sticker);
}
for (auto j = set.stickers.cbegin(), e = set.stickers.cend(); j != e; ++j) {
Serialize::Document::writeToStream(stream, *j);
}
if (AppVersion > 1002008) {
stream << qint32(set.dates.size());
if (!set.dates.empty()) {
Assert(set.dates.size() == set.stickers.size());
for (const auto date : set.dates) {
stream << qint32(date);
}
stream << qint32(set.dates.size());
if (!set.dates.empty()) {
Assert(set.dates.size() == set.stickers.size());
for (const auto date : set.dates) {
stream << qint32(date);
}
}
if (AppVersion > 9018) {
stream << qint32(set.emoji.size());
for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) {
stream << j.key()->id() << qint32(j->size());
for (int32 k = 0, l = j->size(); k < l; ++k) {
stream << quint64(j->at(k)->id);
}
stream << qint32(set.emoji.size());
for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) {
stream << j.key()->id() << qint32(j->size());
for (const auto sticker : *j) {
stream << quint64(sticker->id);
}
}
}
@ -3415,9 +3407,11 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
_writeMap();
return;
}
// versionTag + version + count
quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(qint32);
int32 setsCount = 0;
QByteArray hashToWrite;
quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite);
for (const auto &set : sets) {
auto result = checkSet(set);
if (result == StickerSetCheckResult::Abort) {
@ -3427,12 +3421,23 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
}
// id + access + title + shortName + stickersCount + hash + flags + installDate
size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 3;
for (const auto sticker : std::as_const(set.stickers)) {
size += sizeof(quint64) * 2
+ Serialize::stringSize(set.title)
+ Serialize::stringSize(set.shortName)
+ sizeof(qint32) * 4
+ Serialize::storageImageLocationSize(set.thumbnail
? set.thumbnail->location()
: StorageImageLocation());
if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
continue;
}
for (const auto sticker : set.stickers) {
sticker->refreshStickerThumbFileReference();
size += Serialize::Document::sizeInStream(sticker);
}
size += sizeof(qint32); // dates count
size += sizeof(qint32); // datesCount
if (!set.dates.empty()) {
Assert(set.stickers.size() == set.dates.size());
size += set.dates.size() * sizeof(qint32);
@ -3462,8 +3467,11 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
_writeMap(WriteMapWhen::Fast);
}
EncryptedDescriptor data(size);
data.stream << quint32(setsCount) << hashToWrite;
for_const (auto &set, sets) {
data.stream
<< quint32(kStickersVersionTag)
<< qint32(kStickersSerializeVersion)
<< qint32(setsCount);
for (const auto &set : sets) {
auto result = checkSet(set);
if (result == StickerSetCheckResult::Abort) {
return;
@ -3487,54 +3495,60 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
return;
}
bool readingInstalled = (readingFlags == MTPDstickerSet::Flag::f_installed_date);
const auto failed = [&] {
clearKey(stickersKey);
stickersKey = 0;
};
auto &sets = Auth().data().stickerSetsRef();
if (outOrder) outOrder->clear();
quint32 cnt;
QByteArray hash;
stickers.stream >> cnt >> hash; // ignore hash, it is counted
if (readingInstalled && stickers.version < 8019) { // bad data in old caches
cnt += 2; // try to read at least something
quint32 versionTag = 0;
qint32 version = 0;
stickers.stream >> versionTag >> version;
if (versionTag != kStickersVersionTag
|| version <= 0
|| version > kStickersSerializeVersion) {
// Old data, without sticker set thumbnails.
return failed();
}
for (uint32 i = 0; i < cnt; ++i) {
qint32 count = 0;
stickers.stream >> count;
if (!_checkStreamStatus(stickers.stream)
|| (count < 0)
|| (count > kMaxSavedStickerSetsCount)) {
return failed();
}
for (auto i = 0; i != count; ++i) {
quint64 setId = 0, setAccess = 0;
QString setTitle, setShortName;
qint32 scnt = 0;
auto setInstallDate = qint32(0);
qint32 setInstallDate = 0;
qint32 setHash = 0;
MTPDstickerSet::Flags setFlags = 0;
qint32 setFlagsValue = 0;
StorageImageLocation setThumbnail;
stickers.stream
>> setId
>> setAccess
>> setTitle
>> setShortName
>> scnt;
qint32 setHash = 0;
MTPDstickerSet::Flags setFlags = 0;
if (stickers.version > 8033) {
qint32 setFlagsValue = 0;
stickers.stream >> setHash >> setFlagsValue;
setFlags = MTPDstickerSet::Flags::from_raw(setFlagsValue);
if (setFlags & MTPDstickerSet_ClientFlag::f_not_loaded__old) {
setFlags &= ~MTPDstickerSet_ClientFlag::f_not_loaded__old;
setFlags |= MTPDstickerSet_ClientFlag::f_not_loaded;
}
}
if (stickers.version > 1002008) {
stickers.stream >> setInstallDate;
}
if (readingInstalled && stickers.version < 9061) {
setFlags |= MTPDstickerSet::Flag::f_installed_date;
>> scnt
>> setHash
>> setFlagsValue
>> setInstallDate;
setThumbnail = Serialize::readStorageImageLocation(
stickers.version,
stickers.stream);
if (!_checkStreamStatus(stickers.stream)) {
return failed();
}
setFlags = MTPDstickerSet::Flags::from_raw(setFlagsValue);
if (setId == Stickers::DefaultSetId) {
setTitle = lang(lng_stickers_default_set);
setFlags |= MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special;
if (readingInstalled && outOrder && stickers.version < 9061) {
outOrder->push_front(setId);
}
} else if (setId == Stickers::CustomSetId) {
setTitle = qsl("Custom stickers");
setFlags |= MTPDstickerSet_ClientFlag::f_special;
@ -3544,11 +3558,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
} else if (setId == Stickers::FavedSetId) {
setTitle = Lang::Hard::FavedSetTitle();
setFlags |= MTPDstickerSet_ClientFlag::f_special;
} else if (setId) {
if (readingInstalled && outOrder && stickers.version < 9061) {
outOrder->push_back(setId);
}
} else {
} else if (!setId) {
continue;
}
@ -3564,33 +3574,37 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
0,
setHash,
MTPDstickerSet::Flags(setFlags),
setInstallDate));
setInstallDate,
setThumbnail.isNull() ? ImagePtr() : Images::Create(setThumbnail)));
}
auto &set = it.value();
auto inputSet = MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access));
const auto fillStickers = set.stickers.isEmpty();
if (scnt < 0) { // disabled not loaded set
if (!set.count || set.stickers.isEmpty()) {
if (!set.count || fillStickers) {
set.count = -scnt;
}
continue;
}
bool fillStickers = set.stickers.isEmpty();
if (fillStickers) {
set.stickers.reserve(scnt);
set.count = 0;
}
Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName);
OrderedSet<DocumentId> read;
base::flat_set<DocumentId> read;
for (int32 j = 0; j < scnt; ++j) {
auto document = Serialize::Document::readStickerFromStream(stickers.version, stickers.stream, info);
if (!document || !document->sticker()) continue;
if (read.contains(document->id)) continue;
read.insert(document->id);
if (!_checkStreamStatus(stickers.stream)) {
return failed();
} else if (!document
|| !document->sticker()
|| read.contains(document->id)) {
continue;
}
read.emplace(document->id);
if (fillStickers) {
set.stickers.push_back(document);
if (!(set.flags & MTPDstickerSet_ClientFlag::f_special)) {
@ -3602,64 +3616,71 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
}
}
if (stickers.version > 1002008) {
auto datesCount = qint32(0);
stickers.stream >> datesCount;
if (datesCount > 0) {
if (datesCount != scnt) {
// Bad file.
return;
}
qint32 datesCount = 0;
stickers.stream >> datesCount;
if (datesCount > 0) {
if (datesCount != scnt) {
return failed();
}
const auto fillDates = (set.id == Stickers::CloudRecentSetId)
&& (set.stickers.size() == datesCount);
if (fillDates) {
set.dates.clear();
set.dates.reserve(datesCount);
for (auto i = 0; i != datesCount; ++i) {
auto date = qint32();
stickers.stream >> date;
if (set.id == Stickers::CloudRecentSetId) {
set.dates.push_back(TimeId(date));
}
}
for (auto i = 0; i != datesCount; ++i) {
qint32 date = 0;
stickers.stream >> date;
if (fillDates) {
set.dates.push_back(TimeId(date));
}
}
}
if (stickers.version > 9018) {
qint32 emojiCount;
stickers.stream >> emojiCount;
for (int32 j = 0; j < emojiCount; ++j) {
QString emojiString;
qint32 stickersCount;
stickers.stream >> emojiString >> stickersCount;
Stickers::Pack pack;
pack.reserve(stickersCount);
for (int32 k = 0; k < stickersCount; ++k) {
quint64 id;
stickers.stream >> id;
const auto doc = Auth().data().document(id);
if (!doc->sticker()) continue;
qint32 emojiCount = 0;
stickers.stream >> emojiCount;
if (!_checkStreamStatus(stickers.stream) || emojiCount < 0) {
return failed();
}
for (int32 j = 0; j < emojiCount; ++j) {
QString emojiString;
qint32 stickersCount;
stickers.stream >> emojiString >> stickersCount;
Stickers::Pack pack;
pack.reserve(stickersCount);
for (int32 k = 0; k < stickersCount; ++k) {
quint64 id;
stickers.stream >> id;
const auto doc = Auth().data().document(id);
if (!doc->sticker()) continue;
pack.push_back(doc);
}
if (fillStickers) {
if (auto emoji = Ui::Emoji::Find(emojiString)) {
emoji = emoji->original();
set.emoji.insert(emoji, pack);
}
pack.push_back(doc);
}
if (fillStickers) {
if (auto emoji = Ui::Emoji::Find(emojiString)) {
emoji = emoji->original();
set.emoji.insert(emoji, pack);
}
}
}
}
// Read orders of installed and featured stickers.
if (outOrder && stickers.version >= 9061) {
if (outOrder) {
stickers.stream >> *outOrder;
}
if (!_checkStreamStatus(stickers.stream)) {
return failed();
}
// Set flags that we dropped above from the order.
if (readingFlags && outOrder) {
for_const (auto setId, *outOrder) {
for (const auto setId : std::as_const(*outOrder)) {
auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags |= readingFlags;
if (readingInstalled && !it->installDate) {
if ((readingFlags == MTPDstickerSet::Flag::f_installed_date)
&& !it->installDate) {
it->installDate = kDefaultStickerInstallDate;
}
}
@ -3770,7 +3791,8 @@ void importOldRecentStickers() {
(MTPDstickerSet::Flag::f_official
| MTPDstickerSet::Flag::f_installed_date
| MTPDstickerSet_ClientFlag::f_special),
kDefaultStickerInstallDate)).value();
kDefaultStickerInstallDate,
ImagePtr())).value();
auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(
Stickers::CustomSetId,
uint64(0),
@ -3780,7 +3802,8 @@ void importOldRecentStickers() {
0, // hash
(MTPDstickerSet::Flag::f_installed_date
| MTPDstickerSet_ClientFlag::f_special),
kDefaultStickerInstallDate)).value();
kDefaultStickerInstallDate,
ImagePtr())).value();
QMap<uint64, bool> read;
while (!stickers.stream.atEnd()) {