diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 8d3a886c9..9ffde7881 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1005,7 +1005,14 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) Local::writeUserSettings(); } - Local::writeStickers(); + if (it->flags & MTPDstickerSet::Flag::f_installed) { + if (!(it->flags & MTPDstickerSet::Flag::f_archived)) { + Local::writeInstalledStickers(); + } + } + if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { + Local::writeFeaturedStickers(); + } if (App::main()) emit App::main()->stickersUpdated(); } diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 0c61a589d..f3c85d3e2 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1734,8 +1734,20 @@ namespace { App::main()->incrementSticker(result); } if (versionChanged) { - if (result->sticker()) { - Local::writeStickers(); + if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) { + auto it = Global::StickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v); + if (it != Global::StickerSets().cend()) { + if (it->id == Stickers::CloudRecentSetId) { + Local::writeRecentStickers(); + } else if (it->flags & MTPDstickerSet::Flag::f_archived) { + Local::writeArchivedStickers(); + } else if (it->flags & MTPDstickerSet::Flag::f_installed) { + Local::writeInstalledStickers(); + } + if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { + Local::writeFeaturedStickers(); + } + } } auto &items = App::documentItems(); auto i = items.constFind(result); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 6f863e538..a1df6f957 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -35,7 +35,6 @@ namespace Stickers { void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { auto &v = d.vsets.c_vector().v; - auto &sets = Global::RefStickerSets(); auto &order = Global::RefStickerSetsOrder(); Stickers::Order archived; archived.reserve(v.size()); @@ -189,7 +188,7 @@ void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &res Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); } - Local::writeStickers(); + Local::writeInstalledStickers(); emit App::main()->stickersUpdated(); emit installed(_setId); } @@ -734,8 +733,8 @@ void StickersInner::onClearRecent() { } auto &sets = Global::RefStickerSets(); - sets.remove(Stickers::CloudRecentSetId); - sets.remove(Stickers::CustomSetId); + bool removedCloud = (sets.remove(Stickers::CloudRecentSetId) != 0); + bool removedCustom = (sets.remove(Stickers::CustomSetId) != 0); auto &recent = cGetRecentStickers(); if (!recent.isEmpty()) { @@ -743,7 +742,8 @@ void StickersInner::onClearRecent() { Local::writeUserSettings(); } - Local::writeStickers(); + if (removedCustom) Local::writeInstalledStickers(); + if (removedCloud) Local::writeRecentStickers(); emit App::main()->updateStickers(); rebuild(); @@ -833,8 +833,10 @@ void StickersInner::installSet(uint64 setId) { MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersInner::installDone), rpcFail(&StickersInner::installFail, setId)); + auto flags = it->flags; it->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread); it->flags |= MTPDstickerSet::Flag::f_installed; + auto changedFlags = flags ^ it->flags; auto &order = Global::RefStickerSetsOrder(); int insertAtIndex = 0, currentIndex = order.indexOf(setId); @@ -855,14 +857,16 @@ void StickersInner::installSet(uint64 setId) { sets.erase(custom); } } - Local::writeStickers(); + Local::writeInstalledStickers(); + if (changedFlags & MTPDstickerSet_ClientFlag::f_unread) Local::writeFeaturedStickers(); emit App::main()->stickersUpdated(); } void StickersInner::installDone(const MTPmessages_StickerSetInstallResult &result) { if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); - Local::writeStickers(); + Local::writeInstalledStickers(); + Local::writeArchivedStickers(); emit App::main()->stickersUpdated(); } @@ -895,7 +899,7 @@ bool StickersInner::installFail(uint64 setId, const RPCError &error) { order.removeAt(currentIndex); } - Local::writeStickers(); + Local::writeInstalledStickers(); emit App::main()->stickersUpdated(); Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers); @@ -1098,7 +1102,7 @@ void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) } void StickersInner::readFeaturedDone(const MTPBool &result) { - Local::writeStickers(); + Local::writeFeaturedStickers(); emit App::main()->stickersUpdated(); } @@ -1121,13 +1125,7 @@ Stickers::Order StickersInner::getOrder() const { Stickers::Order result; result.reserve(_rows.size()); for (int32 i = 0, l = _rows.size(); i < l; ++i) { - if (_rows.at(i)->disabled) { - auto it = Global::StickerSets().constFind(_rows.at(i)->id); - if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_official)) { - continue; - } - } - if (_rows.at(i)->recent) { + if (_rows.at(i)->disabled || _rows.at(i)->recent) { continue; } result.push_back(_rows.at(i)->id); @@ -1161,6 +1159,9 @@ StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) , _inner(section) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) { + if (section == Section::Archived) { + Local::readArchivedStickers(); + } setup(); } @@ -1169,6 +1170,7 @@ StickersBox::StickersBox(const Stickers::Order &archivedIds) : ItemListBox(st::b , _inner(archivedIds) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { + Local::readArchivedStickers(); setup(); } @@ -1299,6 +1301,14 @@ void StickersBox::closePressed() { } } +StickersBox::~StickersBox() { + if (_section == Section::Featured) { + Local::writeFeaturedStickers(); + } else if (_section == Section::Archived) { + Local::writeArchivedStickers(); + } +} + void StickersBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _inner->resize(width(), _inner->height()); @@ -1387,7 +1397,9 @@ void StickersBox::onSave() { // Clear all installed flags, set only for sets from order. for (auto &set : sets) { - set.flags &= ~MTPDstickerSet::Flag::f_installed; + if (!(set.flags & MTPDstickerSet::Flag::f_archived)) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; + } } auto &order(Global::RefStickerSetsOrder()); @@ -1407,6 +1419,7 @@ void StickersBox::onSave() { for (auto it = sets.begin(); it != sets.cend();) { if ((it->flags & MTPDstickerSet_ClientFlag::f_featured) || (it->flags & MTPDstickerSet::Flag::f_installed) + || (it->flags & MTPDstickerSet::Flag::f_archived) || (it->flags & MTPDstickerSet_ClientFlag::f_special)) { ++it; } else { @@ -1414,7 +1427,7 @@ void StickersBox::onSave() { } } - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); emit App::main()->stickersUpdated(); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 44d60e770..4dfc9fcb1 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -144,6 +144,8 @@ public: void closePressed(); + ~StickersBox(); + public slots: void onStickersUpdated(); diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 6d86f12d4..a3327c608 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -1518,7 +1518,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { if (it->stickers.isEmpty()) { sets.erase(it); } - Local::writeStickers(); + Local::writeInstalledStickers(); refresh = true; break; } @@ -3651,8 +3651,9 @@ void EmojiPan::onSwitch() { } void EmojiPan::onRemoveSet(quint64 setId) { - auto it = Global::StickerSets().constFind(setId); - if (it != Global::StickerSets().cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { + auto &sets = Global::StickerSets(); + auto it = sets.constFind(setId); + if (it != sets.cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { _removingSetId = it->id; ConfirmBox *box = new ConfirmBox(lng_stickers_remove_pack(lt_sticker_pack, it->title), lang(lng_box_remove)); connect(box, SIGNAL(confirmed()), this, SLOT(onRemoveSetSure())); @@ -3663,8 +3664,9 @@ void EmojiPan::onRemoveSet(quint64 setId) { void EmojiPan::onRemoveSetSure() { Ui::hideLayer(); - auto it = Global::RefStickerSets().find(_removingSetId); - if (it != Global::RefStickerSets().cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { + auto &sets = Global::RefStickerSets(); + auto it = sets.find(_removingSetId); + if (it != sets.cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { if (it->id && it->access) { MTP::send(MTPmessages_UninstallStickerSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)))); } else if (!it->shortName.isEmpty()) { @@ -3682,12 +3684,12 @@ void EmojiPan::onRemoveSetSure() { } it->flags &= ~MTPDstickerSet::Flag::f_installed; if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { - Global::RefStickerSets().erase(it); + sets.erase(it); } int removeIndex = Global::StickerSetsOrder().indexOf(_removingSetId); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); refreshStickers(); - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); } _removingSetId = 0; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 0e2bcfacb..59630d7fc 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3663,7 +3663,9 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { auto &sets = Global::RefStickerSets(); QMap setsToRequest; for (auto &set : sets) { - set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing + if (!(set.flags & MTPDstickerSet::Flag::f_archived)) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing + } } for_const (auto &setData, d_sets) { if (setData.type() == mtpc_stickerSet) { @@ -3682,6 +3684,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured); bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special); + bool archived = (it->flags & MTPDstickerSet::Flag::f_archived); if (!installed) { // remove not mine sets from recent stickers for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) { if (it->stickers.indexOf(i->first) >= 0) { @@ -3692,7 +3695,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { } } } - if (installed || featured || special) { + if (installed || featured || special || archived) { ++it; } else { it = sets.erase(it); @@ -3710,7 +3713,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { App::api()->requestStickerSets(); } - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); if (App::main()) emit App::main()->stickersUpdated(); @@ -3797,7 +3800,7 @@ void HistoryWidget::recentStickersGot(const MTPmessages_RecentStickers &stickers LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countRecentStickersHash())); } - Local::writeStickers(); + Local::writeRecentStickers(); if (App::main()) emit App::main()->stickersUpdated(); } @@ -3875,7 +3878,8 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured); bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special); - if (installed || featured || special) { + bool archived = (it->flags & MTPDstickerSet::Flag::f_archived); + if (installed || featured || special || archived) { if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { ++unreadCount; } @@ -3897,7 +3901,7 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic App::api()->requestStickerSets(); } - Local::writeStickers(); + Local::writeFeaturedStickers(); if (App::main()) emit App::main()->stickersUpdated(); } diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 6ebdbea10..c365e6606 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -479,11 +479,12 @@ namespace { lskBackground = 0x08, // no data lskUserSettings = 0x09, // no data lskRecentHashtagsAndBots = 0x0a, // no data - lskStickers = 0x0b, // no data + lskStickersOld = 0x0b, // no data lskSavedPeers = 0x0c, // no data lskReportSpamStatuses = 0x0d, // no data lskSavedGifsOld = 0x0e, // no data lskSavedGifs = 0x0f, // no data + lskStickersKeys = 0x10, // no data }; enum { @@ -571,7 +572,9 @@ namespace { uint64 _storageWebFilesSize = 0; FileKey _locationsKey = 0, _reportSpamStatusesKey = 0; - FileKey _recentStickersKeyOld = 0, _stickersKey = 0, _savedGifsKey = 0; + FileKey _recentStickersKeyOld = 0; + FileKey _installedStickersKey = 0, _featuredStickersKey = 0, _recentStickersKey = 0, _archivedStickersKey = 0; + FileKey _savedGifsKey = 0; FileKey _backgroundKey = 0; bool _backgroundWasRead = false; @@ -1724,7 +1727,9 @@ namespace { StorageMap imagesMap, stickerImagesMap, audiosMap; qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; quint64 locationsKey = 0, reportSpamStatusesKey = 0; - quint64 recentStickersKeyOld = 0, stickersKey = 0, savedGifsKey = 0; + quint64 recentStickersKeyOld = 0; + quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, archivedStickersKey = 0; + quint64 savedGifsKey = 0; quint64 backgroundKey = 0, userSettingsKey = 0, recentHashtagsAndBotsKey = 0, savedPeersKey = 0; while (!map.stream.atEnd()) { quint32 keyType; @@ -1805,8 +1810,11 @@ namespace { case lskRecentHashtagsAndBots: { map.stream >> recentHashtagsAndBotsKey; } break; - case lskStickers: { - map.stream >> stickersKey; + case lskStickersOld: { + map.stream >> installedStickersKey; + } break; + case lskStickersKeys: { + map.stream >> installedStickersKey >> featuredStickersKey >> recentStickersKey >> archivedStickersKey; } break; case lskSavedGifsOld: { quint64 key; @@ -1841,7 +1849,10 @@ namespace { _locationsKey = locationsKey; _reportSpamStatusesKey = reportSpamStatusesKey; _recentStickersKeyOld = recentStickersKeyOld; - _stickersKey = stickersKey; + _installedStickersKey = installedStickersKey; + _featuredStickersKey = featuredStickersKey; + _recentStickersKey = recentStickersKey; + _archivedStickersKey = archivedStickersKey; _savedGifsKey = savedGifsKey; _savedPeersKey = savedPeersKey; _backgroundKey = backgroundKey; @@ -1914,7 +1925,9 @@ namespace { if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64); - if (_stickersKey) mapSize += sizeof(quint32) + sizeof(quint64); + if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) { + mapSize += sizeof(quint32) + 4 * sizeof(quint64); + } if (_savedGifsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64); @@ -1960,8 +1973,9 @@ namespace { if (_recentStickersKeyOld) { mapData.stream << quint32(lskRecentStickersOld) << quint64(_recentStickersKeyOld); } - if (_stickersKey) { - mapData.stream << quint32(lskStickers) << quint64(_stickersKey); + if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) { + mapData.stream << quint32(lskStickersKeys); + mapData.stream << quint64(_installedStickersKey) << quint64(_featuredStickersKey) << quint64(_recentStickersKey) << quint64(_archivedStickersKey); } if (_savedGifsKey) { mapData.stream << quint32(lskSavedGifs) << quint64(_savedGifsKey); @@ -2247,7 +2261,9 @@ namespace Local { _webFilesMap.clear(); _storageWebFilesSize = 0; _locationsKey = _reportSpamStatusesKey = 0; - _recentStickersKeyOld = _stickersKey = _savedGifsKey = 0; + _recentStickersKeyOld = 0; + _installedStickersKey = _featuredStickersKey = _recentStickersKey = _archivedStickersKey = 0; + _savedGifsKey = 0; _backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = 0; _oldMapVersion = _oldSettingsVersion = 0; _mapChanged = true; @@ -3017,26 +3033,23 @@ namespace Local { } } - void _writeStickerSet(QDataStream &stream, uint64 setId) { - auto it = Global::StickerSets().constFind(setId); - if (it == Global::StickerSets().cend()) return; - - bool notLoaded = (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded); + void _writeStickerSet(QDataStream &stream, const Stickers::Set &set) { + bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); if (notLoaded) { - stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(-it->count) << qint32(it->hash) << qint32(it->flags); + stream << quint64(set.id) << quint64(set.access) << set.title << set.shortName << qint32(-set.count) << qint32(set.hash) << qint32(set.flags); return; } else { - if (it->stickers.isEmpty()) return; + if (set.stickers.isEmpty()) return; } - stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(it->stickers.size()) << qint32(it->hash) << qint32(it->flags); - for (StickerPack::const_iterator j = it->stickers.cbegin(), e = it->stickers.cend(); j != e; ++j) { + stream << quint64(set.id) << quint64(set.access) << set.title << set.shortName << qint32(set.stickers.size()) << qint32(set.hash) << qint32(set.flags); + for (StickerPack::const_iterator j = set.stickers.cbegin(), e = set.stickers.cend(); j != e; ++j) { Serialize::Document::writeToStream(stream, *j); } if (AppVersion > 9018) { - stream << qint32(it->emoji.size()); - for (StickersByEmojiMap::const_iterator j = it->emoji.cbegin(), e = it->emoji.cend(); j != e; ++j) { + stream << qint32(set.emoji.size()); + for (StickersByEmojiMap::const_iterator j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { stream << emojiString(j.key()) << qint32(j->size()); for (int32 k = 0, l = j->size(); k < l; ++k) { stream << quint64(j->at(k)->id); @@ -3045,67 +3058,274 @@ namespace Local { } } - void writeStickers() { + // In generic method _writeStickerSets() we look through all the sets and call a + // callback on each set to see, if we write it, skip it or abort the whole write. + enum class StickerSetCheckResult { + Write, + Skip, + Abort, + }; + + // CheckSet is a functor on Stickers::Set, which returns a StickerSetCheckResult. + template + void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::Order &order) { if (!_working()) return; auto &sets = Global::StickerSets(); if (sets.isEmpty()) { - if (_stickersKey) { - clearKey(_stickersKey); - _stickersKey = 0; + if (stickersKey) { + clearKey(stickersKey); + stickersKey = 0; _mapChanged = true; } _writeMap(); - } else { - int32 setsCount = 0; - QByteArray hashToWrite; - quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite); - for_const (auto &set, sets) { - bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); - if (notLoaded && !(set.flags & MTPDstickerSet_ClientFlag::f_special)) { - if (!(set.flags & MTPDstickerSet::Flag::f_archived) - || (set.flags & MTPDstickerSet::Flag::f_official) - || (set.flags & MTPDstickerSet_ClientFlag::f_featured)) { // waiting to receive - return; - } - } else { - if (set.stickers.isEmpty()) continue; - } - - // id + access + title + shortName + stickersCount + hash + flags - size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 2; - for_const (auto &sticker, set.stickers) { - size += Serialize::Document::sizeInStream(sticker); - } - - if (AppVersion > 9018) { - size += sizeof(qint32); // emojiCount - for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { - size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64)); - } - } - - ++setsCount; - } - size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64)); - size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64)); - - if (!_stickersKey) { - _stickersKey = genKey(); - _mapChanged = true; - _writeMap(WriteMapFast); - } - EncryptedDescriptor data(size); - data.stream << quint32(setsCount) << hashToWrite; - for_const (auto &set, sets) { - _writeStickerSet(data.stream, set.id); - } - data.stream << Global::StickerSetsOrder(); - data.stream << Global::FeaturedStickerSetsOrder(); - - FileWriteDescriptor file(_stickersKey); - file.writeEncrypted(data); + return; } + 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) { + return; + } else if (result == StickerSetCheckResult::Skip) { + continue; + } + + // id + access + title + shortName + stickersCount + hash + flags + size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 2; + for_const (auto &sticker, set.stickers) { + size += Serialize::Document::sizeInStream(sticker); + } + + size += sizeof(qint32); // emojiCount + for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { + size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64)); + } + + ++setsCount; + } + if (!setsCount && order.isEmpty()) { + if (stickersKey) { + clearKey(stickersKey); + stickersKey = 0; + _mapChanged = true; + } + _writeMap(); + return; + } + size += sizeof(qint32) + (order.size() * sizeof(quint64)); + + if (!stickersKey) { + stickersKey = genKey(); + _mapChanged = true; + _writeMap(WriteMapFast); + } + EncryptedDescriptor data(size); + data.stream << quint32(setsCount) << hashToWrite; + for_const (auto &set, sets) { + auto result = checkSet(set); + if (result == StickerSetCheckResult::Abort) { + return; + } else if (result == StickerSetCheckResult::Skip) { + continue; + } + _writeStickerSet(data.stream, set); + } + data.stream << order; + + FileWriteDescriptor file(stickersKey); + file.writeEncrypted(data); + } + + void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr, MTPDstickerSet::Flags readingFlags = 0) { + FileReadDescriptor stickers; + if (!readEncryptedFile(stickers, stickersKey)) { + clearKey(stickersKey); + stickersKey = 0; + _writeMap(); + return; + } + + bool readingInstalled = (readingFlags == qFlags(MTPDstickerSet::Flag::f_installed)); + + auto &sets = Global::RefStickerSets(); + 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 + } + for (uint32 i = 0; i < cnt; ++i) { + quint64 setId = 0, setAccess = 0; + QString setTitle, setShortName; + qint32 scnt = 0; + stickers.stream >> setId >> setAccess >> setTitle >> setShortName >> scnt; + + qint32 setHash = 0, setFlags = 0; + if (stickers.version > 8033) { + stickers.stream >> setHash >> setFlags; + if (setFlags & qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old)) { + setFlags &= ~qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old); + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_not_loaded); + } + } + if (readingInstalled && stickers.version < 9058) { + setFlags |= qFlags(MTPDstickerSet::Flag::f_installed); + } + + if (setId == Stickers::DefaultSetId) { + setTitle = lang(lng_stickers_default_set); + setFlags |= qFlags(MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special); + if (readingInstalled && outOrder && stickers.version < 9058) { + outOrder->push_front(setId); + } + } else if (setId == Stickers::CustomSetId) { + setTitle = lang(lng_custom_stickers); + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); + } else if (setId == Stickers::CloudRecentSetId) { + setTitle = lang(lng_emoji_category0); // Frequently used + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); + } else if (setId) { + if (readingInstalled && outOrder && stickers.version < 9058) { + outOrder->push_back(setId); + } + } else { + continue; + } + + auto it = sets.find(setId); + if (it == sets.cend()) { + // We will set this flags from order lists when reading those stickers. + setFlags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_featured); + it = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))); + } + auto &set = it.value(); + + if (scnt < 0) { // disabled not loaded set + if (!set.count || set.stickers.isEmpty()) { + 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 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 (fillStickers) { + set.stickers.push_back(document); + ++set.count; + } + } + + if (stickers.version > 9018) { + qint32 emojiCount; + stickers.stream >> emojiCount; + for (int32 j = 0; j < emojiCount; ++j) { + QString emojiString; + qint32 stickersCount; + stickers.stream >> emojiString >> stickersCount; + StickerPack pack; + pack.reserve(stickersCount); + for (int32 k = 0; k < stickersCount; ++k) { + quint64 id; + stickers.stream >> id; + DocumentData *doc = App::document(id); + if (!doc || !doc->sticker()) continue; + + pack.push_back(doc); + } + if (fillStickers) { + if (auto e = emojiGetNoColor(emojiFromText(emojiString))) { + set.emoji.insert(e, pack); + } + } + } + } + } + + // Read orders of installed and featured stickers. + if (outOrder && stickers.version >= 9058) { + stickers.stream >> *outOrder; + } + + // Set flags that we dropped above from the order. + if (readingFlags && outOrder) { + for_const (auto setId, *outOrder) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags |= readingFlags; + } + } + } + } + + void writeInstalledStickers() { + _writeStickerSets(_installedStickersKey, [](const Stickers::Set &set) { + if (set.id == Stickers::CloudRecentSetId) { // separate file for recent + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_special) { + if (set.stickers.isEmpty()) { // all other special are "installed" + return StickerSetCheckResult::Skip; + } + } else if (!(set.flags & MTPDstickerSet::Flag::f_installed) || (set.flags & MTPDstickerSet::Flag::f_archived)) { + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) { // waiting to receive + return StickerSetCheckResult::Abort; + } else if (set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Global::StickerSetsOrder()); + } + + void writeFeaturedStickers() { + _writeStickerSets(_featuredStickersKey, [](const Stickers::Set &set) { + if (set.id == Stickers::CloudRecentSetId) { // separate file for recent + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_special) { + return StickerSetCheckResult::Skip; + } else if (!(set.flags & MTPDstickerSet_ClientFlag::f_featured)) { + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) { // waiting to receive + return StickerSetCheckResult::Abort; + } else if (set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Global::FeaturedStickerSetsOrder()); + } + + void writeRecentStickers() { + _writeStickerSets(_recentStickersKey, [](const Stickers::Set &set) { + if (set.id != Stickers::CloudRecentSetId || set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Stickers::Order()); + } + + void writeArchivedStickers() { + _writeStickerSets(_archivedStickersKey, [](const Stickers::Set &set) { + if (!(set.flags & MTPDstickerSet::Flag::f_archived) || set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Stickers::Order()); } void importOldRecentStickers() { @@ -3176,7 +3396,7 @@ namespace Local { } if (custom.stickers.isEmpty()) sets.remove(Stickers::CustomSetId); - writeStickers(); + writeInstalledStickers(); writeUserSettings(); clearKey(_recentStickersKeyOld); @@ -3184,145 +3404,41 @@ namespace Local { _writeMap(); } - void readStickers() { - if (!_stickersKey) { + void readInstalledStickers() { + if (!_installedStickersKey) { return importOldRecentStickers(); } - FileReadDescriptor stickers; - if (!readEncryptedFile(stickers, _stickersKey)) { - clearKey(_stickersKey); - _stickersKey = 0; - _writeMap(); - return; - } + Global::RefStickerSets().clear(); + _readStickerSets(_installedStickersKey, &Global::RefStickerSetsOrder(), qFlags(MTPDstickerSet::Flag::f_installed)); + } - auto &sets = Global::RefStickerSets(); - sets.clear(); + void readFeaturedStickers() { + _readStickerSets(_featuredStickersKey, &Global::RefFeaturedStickerSetsOrder(), qFlags(MTPDstickerSet_ClientFlag::f_featured)); - auto &order = Global::RefStickerSetsOrder(); - order.clear(); - - auto &featuredOrder = Global::RefFeaturedStickerSetsOrder(); - featuredOrder.clear(); - - quint32 cnt; - QByteArray hash; - stickers.stream >> cnt >> hash; // ignore hash, it is counted - if (stickers.version < 8019) { // bad data in old caches - cnt += 2; // try to read at least something - } - for (uint32 i = 0; i < cnt; ++i) { - quint64 setId = 0, setAccess = 0; - QString setTitle, setShortName; - qint32 scnt = 0; - stickers.stream >> setId >> setAccess >> setTitle >> setShortName >> scnt; - - qint32 setHash = 0, setFlags = 0; - if (stickers.version > 8033) { - stickers.stream >> setHash >> setFlags; - if (setFlags & qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old)) { - setFlags &= ~qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old); - setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_not_loaded); - } - } - if (stickers.version < 9058) { - setFlags |= qFlags(MTPDstickerSet::Flag::f_installed); - } - - if (setId == Stickers::DefaultSetId) { - setTitle = lang(lng_stickers_default_set); - setFlags |= qFlags(MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special); - if (stickers.version < 9058) { - order.push_front(setId); - } - } else if (setId == Stickers::CustomSetId) { - setTitle = lang(lng_custom_stickers); - setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); - } else if (setId == Stickers::CloudRecentSetId) { - setTitle = lang(lng_emoji_category0); // Frequently used - setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); - } else if (setId) { - if (stickers.version < 9058) { - order.push_back(setId); - } - } else { - continue; - } - - auto &set = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value(); - // We will set this flags from order lists below. - set.flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_featured); - if (scnt < 0) { // disabled not loaded set - set.count = -scnt; - continue; - } - - set.stickers.reserve(scnt); - - Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName); - OrderedSet 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); - - set.stickers.push_back(document); - ++set.count; - } - - if (stickers.version > 9018) { - qint32 emojiCount; - stickers.stream >> emojiCount; - for (int32 j = 0; j < emojiCount; ++j) { - QString emojiString; - qint32 stickersCount; - stickers.stream >> emojiString >> stickersCount; - StickerPack pack; - pack.reserve(stickersCount); - for (int32 k = 0; k < stickersCount; ++k) { - quint64 id; - stickers.stream >> id; - DocumentData *doc = App::document(id); - if (!doc || !doc->sticker()) continue; - - pack.push_back(doc); - } - if (EmojiPtr e = emojiGetNoColor(emojiFromText(emojiString))) { - set.emoji.insert(e, pack); - } - } - } - } - - // Read orders of installed and featured stickers. - if (stickers.version >= 9058) { - stickers.stream >> order; - stickers.stream >> featuredOrder; - } - - // Set flags and count unread featured sets. - for_const (auto setId, order) { - auto it = sets.find(setId); - if (it != sets.cend()) { - it->flags |= MTPDstickerSet::Flag::f_installed; - } - } + auto &sets = Global::StickerSets(); int unreadCount = 0; - for_const (auto setId, featuredOrder) { - auto it = sets.find(setId); - if (it != sets.cend()) { - it->flags |= MTPDstickerSet_ClientFlag::f_featured; - if (it->flags & MTPDstickerSet_ClientFlag::f_unread) { - ++unreadCount; - } + for_const (auto setId, Global::FeaturedStickerSetsOrder()) { + auto it = sets.constFind(setId); + if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { + ++unreadCount; } } Global::SetFeaturedStickerSetsUnreadCount(unreadCount); } + void readRecentStickers() { + _readStickerSets(_recentStickersKey); + } + + void readArchivedStickers() { + static bool archivedStickersRead = false; + if (!archivedStickersRead) { + _readStickerSets(_archivedStickersKey); + archivedStickersRead = true; + } + } + int32 countStickersHash(bool checkOfficial) { uint32 acc = 0; bool foundOfficial = false, foundBad = false;; @@ -3941,8 +4057,8 @@ namespace Local { _recentStickersKeyOld = 0; _mapChanged = true; } - if (_stickersKey) { - _stickersKey = 0; + if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) { + _installedStickersKey = _featuredStickersKey = _recentStickersKey = _archivedStickersKey = 0; _mapChanged = true; } if (_recentHashtagsAndBotsKey) { diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index a4909037d..786a10850 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -153,8 +153,14 @@ namespace Local { void cancelTask(TaskId id); - void writeStickers(); - void readStickers(); + void writeInstalledStickers(); + void writeFeaturedStickers(); + void writeRecentStickers(); + void writeArchivedStickers(); + void readInstalledStickers(); + void readFeaturedStickers(); + void readRecentStickers(); + void readArchivedStickers(); int32 countStickersHash(bool checkOfficial = false); int32 countRecentStickersHash(); int32 countFeaturedStickersHash(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 9c5c00f3d..44d597b81 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3298,7 +3298,9 @@ void MainWidget::start(const MTPUser &user) { } _started = true; App::wnd()->sendServiceHistoryRequest(); - Local::readStickers(); + Local::readInstalledStickers(); + Local::readFeaturedStickers(); + Local::readRecentStickers(); Local::readSavedGifs(); _history->start(); } @@ -3676,7 +3678,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) { if (!sticker || !sticker->sticker()) return; if (sticker->sticker()->set.type() == mtpc_inputStickerSetEmpty) return; - bool writeStickers = false; + bool writeRecentStickers = false; auto &sets = Global::RefStickerSets(); auto it = sets.find(Stickers::CloudRecentSetId); if (it == sets.cend()) { @@ -3692,29 +3694,30 @@ void MainWidget::incrementSticker(DocumentData *sticker) { } if (index) { it->stickers.push_front(sticker); - writeStickers = true; + writeRecentStickers = true; } // Remove that sticker from old recent, now it is in cloud recent stickers. - bool writeRecent = false; + bool writeOldRecent = false; auto &recent = cGetRecentStickers(); for (auto i = recent.begin(), e = recent.end(); i != e; ++i) { if (i->first == sticker) { - writeRecent = true; + writeOldRecent = true; recent.erase(i); break; } } while (!recent.isEmpty() && it->stickers.size() + recent.size() > Global::StickersRecentLimit()) { - writeRecent = true; + writeOldRecent = true; recent.pop_back(); } - if (writeRecent) { + if (writeOldRecent) { Local::writeUserSettings(); } // Remove that sticker from custom stickers, now it is in cloud recent stickers. + bool writeInstalledStickers = false; auto custom = sets.find(Stickers::CustomSetId); if (custom != sets.cend()) { int removeIndex = custom->stickers.indexOf(sticker); @@ -3723,12 +3726,15 @@ void MainWidget::incrementSticker(DocumentData *sticker) { if (custom->stickers.isEmpty()) { sets.erase(custom); } - writeStickers = true; + writeInstalledStickers = true; } } - if (writeStickers) { - Local::writeStickers(); + if (writeInstalledStickers) { + Local::writeInstalledStickers(); + } + if (writeRecentStickers) { + Local::writeRecentStickers(); } _history->updateRecentStickers(); } @@ -4673,6 +4679,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed)); } else { it->flags |= MTPDstickerSet::Flag::f_installed; + it->flags &= ~MTPDstickerSet::Flag::f_archived; } const auto &v(set.vdocuments.c_vector().v); @@ -4722,7 +4729,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { sets.erase(custom); } } - Local::writeStickers(); + Local::writeInstalledStickers(); emit stickersUpdated(); } } @@ -4744,7 +4751,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::main()->updateStickers(); } else { Global::SetStickerSetsOrder(result); - Local::writeStickers(); + Local::writeInstalledStickers(); emit stickersUpdated(); } } break; @@ -4767,7 +4774,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } if (Global::FeaturedStickerSetsUnreadCount()) { Global::SetFeaturedStickerSetsUnreadCount(0); - Local::writeStickers(); + Local::writeFeaturedStickers(); emit stickersUpdated(); } } break;