Request and cache featured emoji sets.

This commit is contained in:
John Preston 2022-07-22 16:08:10 +03:00
parent b31a3ba5a3
commit b4b55973b5
10 changed files with 185 additions and 70 deletions

View file

@ -60,6 +60,23 @@ namespace {
: 0;
}
[[nodiscard]] uint64 CountFeaturedHash(
not_null<Main::Session*> session,
const Data::StickersSetsOrder &order) {
auto result = HashInit();
const auto &sets = session->data().stickers().sets();
for (const auto setId : order) {
HashUpdate(result, setId);
const auto it = sets.find(setId);
if (it != sets.cend()
&& (it->second->flags & Data::StickersSetFlag::Unread)) {
HashUpdate(result, 1);
}
}
return HashFinalize(result);
}
} // namespace
uint64 CountStickersHash(
@ -104,19 +121,15 @@ uint64 CountFavedStickersHash(not_null<Main::Session*> session) {
}
uint64 CountFeaturedStickersHash(not_null<Main::Session*> session) {
auto result = HashInit();
const auto &sets = session->data().stickers().sets();
const auto &featured = session->data().stickers().featuredSetsOrder();
for (const auto setId : featured) {
HashUpdate(result, setId);
return CountFeaturedHash(
session,
session->data().stickers().featuredSetsOrder());
}
const auto it = sets.find(setId);
if (it != sets.cend()
&& (it->second->flags & Data::StickersSetFlag::Unread)) {
HashUpdate(result, 1);
}
}
return HashFinalize(result);
uint64 CountFeaturedEmojiHash(not_null<Main::Session*> session) {
return CountFeaturedHash(
session,
session->data().stickers().featuredEmojiSetsOrder());
}
uint64 CountSavedGifsHash(not_null<Main::Session*> session) {

View file

@ -25,9 +25,12 @@ namespace Api {
[[nodiscard]] uint64 CountRecentStickersHash(
not_null<Main::Session*> session,
bool attached = false);
[[nodiscard]] uint64 CountFavedStickersHash(not_null<Main::Session*> session);
[[nodiscard]] uint64 CountFavedStickersHash(
not_null<Main::Session*> session);
[[nodiscard]] uint64 CountFeaturedStickersHash(
not_null<Main::Session*> session);
[[nodiscard]] uint64 CountFeaturedEmojiHash(
not_null<Main::Session*> session);
[[nodiscard]] uint64 CountSavedGifsHash(not_null<Main::Session*> session);
[[nodiscard]] inline uint64 HashInit() {

View file

@ -2526,6 +2526,7 @@ void ApiWrap::updateStickers() {
requestRecentStickers(now);
requestFavedStickers(now);
requestFeaturedStickers(now);
requestFeaturedEmoji(now);
requestSavedGifs(now);
}
@ -2778,28 +2779,33 @@ void ApiWrap::requestFeaturedStickers(TimeId now) {
_featuredStickersUpdateRequest = request(MTPmessages_GetFeaturedStickers(
MTP_long(Api::CountFeaturedStickersHash(_session))
)).done([=](const MTPmessages_FeaturedStickers &result) {
_session->data().stickers().setLastFeaturedUpdate(crl::now());
_featuredStickersUpdateRequest = 0;
switch (result.type()) {
case mtpc_messages_featuredStickersNotModified: return;
case mtpc_messages_featuredStickers: {
auto &d = result.c_messages_featuredStickers();
_session->data().stickers().featuredSetsReceived(
d.vsets().v,
d.vunread().v,
d.vhash().v);
} return;
default: Unexpected("Type in ApiWrap::featuredStickersDone()");
}
_session->data().stickers().featuredSetsReceived(result);
}).fail([=] {
_session->data().stickers().setLastFeaturedUpdate(crl::now());
_featuredStickersUpdateRequest = 0;
_session->data().stickers().setLastFeaturedUpdate(crl::now());
LOG(("App Fail: Failed to get featured stickers!"));
}).send();
}
void ApiWrap::requestFeaturedEmoji(TimeId now) {
if (!_session->data().stickers().featuredEmojiUpdateNeeded(now)
|| _featuredEmojiUpdateRequest) {
return;
}
_featuredEmojiUpdateRequest = request(
MTPmessages_GetFeaturedEmojiStickers(
MTP_long(Api::CountFeaturedStickersHash(_session)))
).done([=](const MTPmessages_FeaturedStickers &result) {
_featuredEmojiUpdateRequest = 0;
_session->data().stickers().featuredEmojiSetsReceived(result);
}).fail([=] {
_featuredEmojiUpdateRequest = 0;
_session->data().stickers().setLastFeaturedEmojiUpdate(crl::now());
LOG(("App Fail: Failed to get featured emoji!"));
}).send();
}
void ApiWrap::requestSavedGifs(TimeId now) {
if (!_session->data().stickers().savedGifsUpdateNeeded(now)
|| _savedGifsUpdateRequest) {

View file

@ -445,6 +445,7 @@ private:
void requestRecentStickersWithHash(uint64 hash, bool attached = false);
void requestFavedStickers(TimeId now);
void requestFeaturedStickers(TimeId now);
void requestFeaturedEmoji(TimeId now);
void requestSavedGifs(TimeId now);
void readFeaturedSets();
@ -564,6 +565,7 @@ private:
mtpRequestId _recentAttachedStickersUpdateRequest = 0;
mtpRequestId _favedStickersUpdateRequest = 0;
mtpRequestId _featuredStickersUpdateRequest = 0;
mtpRequestId _featuredEmojiUpdateRequest = 0;
mtpRequestId _savedGifsUpdateRequest = 0;
base::Timer _featuredSetsReadTimer;

View file

@ -392,10 +392,12 @@ EmojiListWidget::EmojiListWidget(
resizeToWidth(width());
}, lifetime());
Data::AmPremiumValue(
&controller->session()
) | rpl::start_with_next([=] {
update();
rpl::combine(
Data::AmPremiumValue(&controller->session()),
controller->session().premiumPossibleValue()
) | rpl::skip(1) | rpl::start_with_next([=] {
refreshCustom();
resizeToWidth(width());
}, lifetime());
}
@ -1221,8 +1223,9 @@ void EmojiListWidget::refreshCustom() {
auto old = base::take(_custom);
const auto owner = &controller()->session().data();
const auto &order = owner->stickers().emojiSetsOrder();
const auto &featured = owner->stickers().featuredEmojiSetsOrder();
const auto &sets = owner->stickers().sets();
for (const auto setId : order) {
for (const auto setId : ranges::views::concat(order, featured)) {
auto it = sets.find(setId);
if (it == sets.cend() || it->second->stickers.isEmpty()) {
continue;

View file

@ -401,14 +401,19 @@ void Stickers::installLocally(uint64 setId) {
}
const auto set = it->second.get();
auto flags = set->flags;
const auto flags = set->flags;
set->flags &= ~(SetFlag::Archived | SetFlag::Unread);
set->flags |= SetFlag::Installed;
set->installDate = base::unixtime::now();
auto changedFlags = flags ^ set->flags;
const auto masks = !!(flags & SetFlag::Masks);
auto &order = masks ? maskSetsOrderRef() : setsOrderRef();
const auto isMasks = (set->type() == StickersType::Masks);
const auto isEmoji = (set->type() == StickersType::Emoji);
auto &order = isEmoji
? emojiSetsOrderRef()
: isMasks
? maskSetsOrderRef()
: setsOrderRef();
int insertAtIndex = 0, currentIndex = order.indexOf(setId);
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
@ -429,17 +434,21 @@ void Stickers::installLocally(uint64 setId) {
}
}
session().local().writeInstalledStickers();
if (changedFlags & SetFlag::Unread) {
session().local().writeFeaturedStickers();
if (!isMasks && (changedFlags & SetFlag::Unread)) {
if (isEmoji) {
session().local().writeFeaturedCustomEmoji();
} else {
session().local().writeFeaturedStickers();
}
}
if (changedFlags & SetFlag::Archived) {
auto &archivedOrder = masks
if (!isEmoji && (changedFlags & SetFlag::Archived)) {
auto &archivedOrder = isMasks
? archivedMaskSetsOrderRef()
: archivedSetsOrderRef();
const auto index = archivedOrder.indexOf(setId);
if (index >= 0) {
archivedOrder.removeAt(index);
if (masks) {
if (isMasks) {
session().local().writeArchivedMasks();
} else {
session().local().writeArchivedStickers();
@ -922,27 +931,51 @@ void Stickers::specialSetReceived(
}
void Stickers::featuredSetsReceived(
const QVector<MTPStickerSetCovered> &list,
const QVector<MTPlong> &unread,
uint64 hash) {
const MTPmessages_FeaturedStickers &result) {
setLastFeaturedUpdate(crl::now());
result.match([](const MTPDmessages_featuredStickersNotModified &) {
}, [&](const MTPDmessages_featuredStickers &data) {
featuredReceived(data, StickersType::Stickers);
});
}
void Stickers::featuredEmojiSetsReceived(
const MTPmessages_FeaturedStickers &result) {
setLastFeaturedEmojiUpdate(crl::now());
result.match([](const MTPDmessages_featuredStickersNotModified &) {
}, [&](const MTPDmessages_featuredStickers &data) {
featuredReceived(data, StickersType::Emoji);
});
}
void Stickers::featuredReceived(
const MTPDmessages_featuredStickers &data,
StickersType type) {
const auto &list = data.vsets().v;
const auto &unread = data.vunread().v;
const auto hash = data.vhash().v;
auto &&unreadIds = ranges::views::all(
unread
) | ranges::views::transform([](const MTPlong &id) {
return id.v;
});
) | ranges::views::transform(&MTPlong::v);
const auto unreadMap = base::flat_set<uint64>{
unreadIds.begin(),
unreadIds.end()
};
auto &setsOrder = featuredSetsOrderRef();
const auto isEmoji = (type == StickersType::Emoji);
auto &setsOrder = isEmoji
? featuredEmojiSetsOrderRef()
: featuredSetsOrderRef();
setsOrder.clear();
auto &sets = setsRef();
auto setsToRequest = base::flat_map<uint64, uint64>();
for (auto &[id, set] : sets) {
// Mark for removing.
set->flags &= ~SetFlag::Featured;
if (set->type() == type) {
set->flags &= ~SetFlag::Featured;
}
}
for (const auto &entry : list) {
const auto data = entry.match([&](const auto &data) {
@ -1015,7 +1048,9 @@ void Stickers::featuredSetsReceived(
bool archived = (set->flags & SetFlag::Archived);
if (installed || featured || special || archived) {
if (featured && (set->flags & SetFlag::Unread)) {
++unreadCount;
if (!(set->flags & SetFlag::Emoji)) {
++unreadCount;
}
}
++it;
} else {
@ -1024,7 +1059,9 @@ void Stickers::featuredSetsReceived(
}
setFeaturedSetsUnreadCount(unreadCount);
const auto counted = Api::CountFeaturedStickersHash(&session());
const auto counted = isEmoji
? Api::CountFeaturedEmojiHash(&session())
: Api::CountFeaturedStickersHash(&session());
if (counted != hash) {
LOG(("API Error: "
"received featured stickers hash %1 while counted hash is %2"
@ -1039,8 +1076,11 @@ void Stickers::featuredSetsReceived(
}
api.requestStickerSets();
}
session().local().writeFeaturedStickers();
if (isEmoji) {
session().local().writeFeaturedCustomEmoji();
} else {
session().local().writeFeaturedStickers();
}
notifyUpdated();
}
@ -1411,8 +1451,8 @@ void Stickers::feedSetStickers(
}
}
const auto isEmoji = !!(set->flags & SetFlag::Emoji);
const auto isMasks = !!(set->flags & SetFlag::Masks);
const auto isEmoji = (set->type() == StickersType::Emoji);
const auto isMasks = (set->type() == StickersType::Masks);
set->stickers = pack;
set->emoji.clear();
for (auto i = 0, l = int(packs.size()); i != l; ++i) {
@ -1449,7 +1489,12 @@ void Stickers::feedSetStickers(
}
}
if (set->flags & SetFlag::Featured) {
session().local().writeFeaturedStickers();
if (isEmoji) {
session().local().writeFeaturedCustomEmoji();
} else if (isMasks) {
} else {
session().local().writeFeaturedStickers();
}
}
if (wasArchived != isArchived) {
if (isEmoji) {

View file

@ -126,6 +126,12 @@ public:
void setLastFeaturedUpdate(crl::time update) {
_lastFeaturedUpdate = update;
}
bool featuredEmojiUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFeaturedEmojiUpdate, now);
}
void setLastFeaturedEmojiUpdate(crl::time update) {
_lastFeaturedEmojiUpdate = update;
}
bool savedGifsUpdateNeeded(crl::time now) const {
return updateNeeded(_lastSavedGifsUpdate, now);
}
@ -171,6 +177,12 @@ public:
StickersSetsOrder &featuredSetsOrderRef() {
return _featuredSetsOrder;
}
const StickersSetsOrder &featuredEmojiSetsOrder() const {
return _featuredEmojiSetsOrder;
}
StickersSetsOrder &featuredEmojiSetsOrderRef() {
return _featuredEmojiSetsOrder;
}
const StickersSetsOrder &archivedSetsOrder() const {
return _archivedSetsOrder;
}
@ -216,10 +228,9 @@ public:
uint64 hash,
const QVector<MTPStickerPack> &packs = QVector<MTPStickerPack>(),
const QVector<MTPint> &usageDates = QVector<MTPint>());
void featuredSetsReceived(
const QVector<MTPStickerSetCovered> &list,
const QVector<MTPlong> &unread,
uint64 hash);
void featuredSetsReceived(const MTPmessages_FeaturedStickers &result);
void featuredEmojiSetsReceived(
const MTPmessages_FeaturedStickers &result);
void gifsReceived(const QVector<MTPDocument> &items, uint64 hash);
std::vector<not_null<DocumentData*>> getListByEmoji(
@ -277,6 +288,9 @@ private:
const QVector<MTPStickerSet> &list,
uint64 hash,
StickersType type);
void featuredReceived(
const MTPDmessages_featuredStickers &data,
StickersType type);
const not_null<Session*> _owner;
rpl::event_stream<> _updated;
@ -291,6 +305,7 @@ private:
crl::time _lastSavedGifsUpdate = 0;
crl::time _lastMasksUpdate = 0;
crl::time _lastEmojiUpdate = 0;
crl::time _lastFeaturedEmojiUpdate = 0;
crl::time _lastRecentAttachedUpdate = 0;
rpl::variable<int> _featuredSetsUnreadCount = 0;
StickersSets _sets;
@ -298,6 +313,7 @@ private:
StickersSetsOrder _maskSetsOrder;
StickersSetsOrder _emojiSetsOrder;
StickersSetsOrder _featuredSetsOrder;
StickersSetsOrder _featuredEmojiSetsOrder;
StickersSetsOrder _archivedSetsOrder;
StickersSetsOrder _archivedMaskSetsOrder;
SavedGifs _savedGifs;

View file

@ -159,6 +159,7 @@ Session::Session(
local().readInstalledMasks();
local().readInstalledCustomEmoji();
local().readFeaturedStickers();
local().readFeaturedCustomEmoji();
local().readRecentStickers();
local().readRecentMasks();
local().readFavedStickers();

View file

@ -205,7 +205,7 @@ base::flat_set<QString> Account::collectGoodNames() const {
_recentMasksKey,
_archivedMasksKey,
_installedCustomEmojiKey,
_recentCustomEmojiKey,
_featuredCustomEmojiKey,
_archivedCustomEmojiKey,
};
auto result = base::flat_set<QString>{
@ -288,7 +288,7 @@ Account::ReadMapResult Account::readMapWith(
quint64 recentStickersKeyOld = 0;
quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0;
quint64 installedMasksKey = 0, recentMasksKey = 0, archivedMasksKey = 0;
quint64 installedCustomEmojiKey = 0, recentCustomEmojiKey = 0, archivedCustomEmojiKey = 0;
quint64 installedCustomEmojiKey = 0, featuredCustomEmojiKey = 0, archivedCustomEmojiKey = 0;
quint64 savedGifsKey = 0;
quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0;
quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0;
@ -394,7 +394,7 @@ Account::ReadMapResult Account::readMapWith(
case lskCustomEmojiKeys: {
map.stream
>> installedCustomEmojiKey
>> recentCustomEmojiKey
>> featuredCustomEmojiKey
>> archivedCustomEmojiKey;
} break;
default:
@ -425,7 +425,7 @@ Account::ReadMapResult Account::readMapWith(
_recentMasksKey = recentMasksKey;
_archivedMasksKey = archivedMasksKey;
_installedCustomEmojiKey = installedCustomEmojiKey;
_recentCustomEmojiKey = recentCustomEmojiKey;
_featuredCustomEmojiKey = featuredCustomEmojiKey;
_archivedCustomEmojiKey = archivedCustomEmojiKey;
_legacyBackgroundKeyDay = legacyBackgroundKeyDay;
_legacyBackgroundKeyNight = legacyBackgroundKeyNight;
@ -534,7 +534,7 @@ void Account::writeMap() {
if (_installedMasksKey || _recentMasksKey || _archivedMasksKey) {
mapSize += sizeof(quint32) + 3 * sizeof(quint64);
}
if (_installedCustomEmojiKey || _recentCustomEmojiKey || _archivedCustomEmojiKey) {
if (_installedCustomEmojiKey || _featuredCustomEmojiKey || _archivedCustomEmojiKey) {
mapSize += sizeof(quint32) + 3 * sizeof(quint64);
}
@ -589,11 +589,11 @@ void Account::writeMap() {
<< quint64(_recentMasksKey)
<< quint64(_archivedMasksKey);
}
if (_installedCustomEmojiKey || _recentCustomEmojiKey || _archivedCustomEmojiKey) {
if (_installedCustomEmojiKey || _featuredCustomEmojiKey || _archivedCustomEmojiKey) {
mapData.stream << quint32(lskCustomEmojiKeys);
mapData.stream
<< quint64(_installedCustomEmojiKey)
<< quint64(_recentCustomEmojiKey)
<< quint64(_featuredCustomEmojiKey)
<< quint64(_archivedCustomEmojiKey);
}
map.writeEncrypted(mapData, _localKey);
@ -618,7 +618,7 @@ void Account::reset() {
_recentMasksKey = 0;
_archivedMasksKey = 0;
_installedCustomEmojiKey = 0;
_recentCustomEmojiKey = 0;
_featuredCustomEmojiKey = 0;
_archivedCustomEmojiKey = 0;
_legacyBackgroundKeyDay = _legacyBackgroundKeyNight = 0;
_settingsKey = _recentHashtagsAndBotsKey = _exportSettingsKey = 0;
@ -2042,7 +2042,7 @@ void Account::writeFeaturedStickers() {
|| set.id == Data::Stickers::CloudRecentAttachedSetId) {
// separate files for them
return StickerSetCheckResult::Skip;
} else if (set.flags & SetFlag::Special) {
} else if (set.flags & (SetFlag::Special | SetFlag::Emoji)) {
return StickerSetCheckResult::Skip;
} else if (!(set.flags & SetFlag::Featured)) {
return StickerSetCheckResult::Skip;
@ -2055,6 +2055,23 @@ void Account::writeFeaturedStickers() {
}, _owner->session().data().stickers().featuredSetsOrder());
}
void Account::writeFeaturedCustomEmoji() {
using SetFlag = Data::StickersSetFlag;
writeStickerSets(_featuredCustomEmojiKey, [](const Data::StickersSet &set) {
if (!(set.flags & SetFlag::Emoji)) {
return StickerSetCheckResult::Skip;
} else if (!(set.flags & SetFlag::Featured)) {
return StickerSetCheckResult::Skip;
} else if (set.flags & SetFlag::NotLoaded) { // waiting to receive
return StickerSetCheckResult::Abort;
} else if (set.stickers.isEmpty()) {
return StickerSetCheckResult::Skip;
}
return StickerSetCheckResult::Write;
}, _owner->session().data().stickers().featuredEmojiSetsOrder());
}
void Account::writeRecentStickers() {
writeStickerSets(_recentStickersKey, [](const Data::StickersSet &set) {
if (set.id != Data::Stickers::CloudRecentSetId
@ -2293,6 +2310,13 @@ void Account::readFeaturedStickers() {
_owner->session().data().stickers().setFeaturedSetsUnreadCount(unreadCount);
}
void Account::readFeaturedCustomEmoji() {
readStickerSets(
_featuredCustomEmojiKey,
&_owner->session().data().stickers().featuredEmojiSetsOrderRef(),
Data::StickersSetFlag::Featured);
}
void Account::readRecentStickers() {
readStickerSets(_recentStickersKey);
}

View file

@ -136,7 +136,9 @@ public:
void readInstalledMasks();
void readRecentMasks();
void writeInstalledCustomEmoji();
void writeFeaturedCustomEmoji();
void readInstalledCustomEmoji();
void readFeaturedCustomEmoji();
void writeRecentHashtagsAndBots();
void readRecentHashtagsAndBots();
@ -287,7 +289,7 @@ private:
FileKey _installedMasksKey = 0;
FileKey _recentMasksKey = 0;
FileKey _installedCustomEmojiKey = 0;
FileKey _recentCustomEmojiKey = 0;
FileKey _featuredCustomEmojiKey = 0;
FileKey _archivedCustomEmojiKey = 0;
qint64 _cacheTotalSizeLimit = 0;