diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index a5717a8cc..226f5e633 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -59,6 +59,7 @@ constexpr auto kFeedMessagesLimit = 50; constexpr auto kReadFeaturedSetsTimeout = TimeMs(1000); constexpr auto kFileLoaderQueueStopTimeout = TimeMs(5000); constexpr auto kFeedReadTimeout = TimeMs(1000); +constexpr auto kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000); bool IsSilentPost(not_null item, bool silent) { const auto history = item->history(); @@ -2199,11 +2200,60 @@ void ApiWrap::updateStickers() { void ApiWrap::setGroupStickerSet(not_null megagroup, const MTPInputStickerSet &set) { Expects(megagroup->mgInfo != nullptr); + megagroup->mgInfo->stickerSet = set; request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send(); _session->data().notifyStickersUpdated(); } +std::vector> *ApiWrap::stickersByEmoji( + not_null emoji) { + const auto it = _stickersByEmoji.find(emoji); + const auto sendRequest = [&] { + if (it == _stickersByEmoji.end()) { + return true; + } + const auto received = it->second.received; + const auto now = getms(true); + return (received > 0) + && (received + kStickersByEmojiInvalidateTimeout) <= now; + }(); + if (sendRequest) { + const auto hash = (it != _stickersByEmoji.end()) + ? it->second.hash + : QString(); + request(MTPmessages_GetStickers( + MTP_flags(MTPmessages_GetStickers::Flag::f_exclude_featured), + MTP_string(emoji->text()), + MTP_string(hash) + )).done([=](const MTPmessages_Stickers &result) { + if (result.type() == mtpc_messages_stickersNotModified) { + return; + } + Assert(result.type() == mtpc_messages_stickers); + const auto &data = result.c_messages_stickers(); + auto &entry = _stickersByEmoji[emoji]; + entry.list.clear(); + entry.list.reserve(data.vstickers.v.size()); + for (const auto &sticker : data.vstickers.v) { + const auto document = Auth().data().document(sticker); + if (document->sticker()) { + entry.list.push_back(document); + } + } + entry.hash = qs(data.vhash); + entry.received = getms(true); + _session->data().notifyStickersUpdated(); + }).send(); + } + if (it == _stickersByEmoji.end()) { + _stickersByEmoji.emplace(emoji, StickersByEmoji()); + } else if (it->second.received > 0) { + return &it->second.list; + } + return nullptr; +} + void ApiWrap::requestStickers(TimeId now) { if (!_session->data().stickersUpdateNeeded(now) || _stickersUpdateRequest) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 78edf5946..563087347 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -129,6 +129,8 @@ public: void setGroupStickerSet( not_null megagroup, const MTPInputStickerSet &set); + std::vector> *stickersByEmoji( + not_null emoji); void joinChannel(ChannelData *channel); void leaveChannel(ChannelData *channel); @@ -279,6 +281,12 @@ private: using MessageDataRequests = QMap; using SharedMediaType = Storage::SharedMediaType; + struct StickersByEmoji { + std::vector> list; + QString hash; + TimeMs received = 0; + }; + void updatesReceived(const MTPUpdates &updates); void checkQuitPreventFinished(); @@ -489,6 +497,8 @@ private: base::Timer _featuredSetsReadTimer; base::flat_set _featuredSetsRead; + base::flat_map, StickersByEmoji> _stickersByEmoji; + base::flat_map _privacySaveRequests; mtpRequestId _contactsRequestId = 0; diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 9192defbb..4eefa76cd 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -324,6 +324,7 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in if (!isHidden()) { hideAnimated(); } + _scroll->scrollToY(0); _mrows.clear(); _hrows.clear(); _brows.clear(); diff --git a/Telegram/SourceFiles/chat_helpers/stickers.cpp b/Telegram/SourceFiles/chat_helpers/stickers.cpp index 9db1abdec..e522a91ac 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers.cpp @@ -670,33 +670,52 @@ Pack GetListByEmoji(not_null emoji) { result = faved; } } - auto &order = Auth().data().stickerSetsOrder(); - for (auto i = 0, l = order.size(); i != l; ++i) { - auto it = sets.find(order[i]); - if (it != sets.cend()) { + const auto addList = [&](const Order &order, MTPDstickerSet::Flag skip) { + for (const auto setId : order) { + auto it = sets.find(setId); + if (it == sets.cend() || (it->flags & skip)) { + continue; + } 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); - } - } + continue; + } + auto i = it->emoji.constFind(original); + if (i == it->emoji.cend()) { + continue; + } + result.reserve(result.size() + i->size()); + for_const (const auto document, *i) { + if (!faved.contains(document)) { + result.push_back(document); } } } - } + }; + + addList( + Auth().data().stickerSetsOrder(), + MTPDstickerSet::Flag::f_archived); + addList( + Auth().data().featuredStickerSetsOrder(), + MTPDstickerSet::Flag::f_installed_date); + if (!setsToRequest.isEmpty()) { for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { Auth().api().scheduleStickerSetRequest(i.key(), i.value()); } Auth().api().requestStickerSets(); } - return result; + if (const auto pack = Auth().api().stickersByEmoji(original)) { + for (const auto document : *pack) { + if (!base::contains(result, document)) { + result.push_back(document); + } + } + return result; + } + return Pack(); } base::optional>> GetEmojiListFromSet( diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index a5ffcd032..58e88a4ca 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -43,13 +43,13 @@ public: return *_session; } - base::Variable &contactsLoaded() { + [[nodiscard]] base::Variable &contactsLoaded() { return _contactsLoaded; } - base::Variable &allChatsLoaded() { + [[nodiscard]] base::Variable &allChatsLoaded() { return _allChatsLoaded; } - base::Observable &moreChatsLoaded() { + [[nodiscard]] base::Observable &moreChatsLoaded() { return _moreChatsLoaded; } @@ -57,7 +57,7 @@ public: not_null item; not_null isVisible; }; - base::Observable &queryItemVisibility() { + [[nodiscard]] base::Observable &queryItemVisibility() { return _queryItemVisibility; } struct IdChange { @@ -65,32 +65,32 @@ public: MsgId oldId = 0; }; void notifyItemIdChange(IdChange event); - rpl::producer itemIdChanged() const; + [[nodiscard]] rpl::producer itemIdChanged() const; void notifyItemLayoutChange(not_null item); - rpl::producer> itemLayoutChanged() const; + [[nodiscard]] rpl::producer> itemLayoutChanged() const; void notifyViewLayoutChange(not_null view); - rpl::producer> viewLayoutChanged() const; + [[nodiscard]] rpl::producer> viewLayoutChanged() const; void requestItemRepaint(not_null item); - rpl::producer> itemRepaintRequest() const; + [[nodiscard]] rpl::producer> itemRepaintRequest() const; void requestViewRepaint(not_null view); - rpl::producer> viewRepaintRequest() const; + [[nodiscard]] rpl::producer> viewRepaintRequest() const; void requestItemResize(not_null item); - rpl::producer> itemResizeRequest() const; + [[nodiscard]] rpl::producer> itemResizeRequest() const; void requestViewResize(not_null view); - rpl::producer> viewResizeRequest() const; + [[nodiscard]] rpl::producer> viewResizeRequest() const; void requestItemViewRefresh(not_null item); - rpl::producer> itemViewRefreshRequest() const; + [[nodiscard]] rpl::producer> itemViewRefreshRequest() const; void requestAnimationPlayInline(not_null item); - rpl::producer> animationPlayInlineRequest() const; + [[nodiscard]] rpl::producer> animationPlayInlineRequest() const; void notifyHistoryUnloaded(not_null history); - rpl::producer> historyUnloaded() const; + [[nodiscard]] rpl::producer> historyUnloaded() const; void notifyItemRemoved(not_null item); - rpl::producer> itemRemoved() const; + [[nodiscard]] rpl::producer> itemRemoved() const; void notifyHistoryCleared(not_null history); - rpl::producer> historyCleared() const; + [[nodiscard]] rpl::producer> historyCleared() const; void notifyHistoryChangeDelayed(not_null history); - rpl::producer> historyChanged() const; + [[nodiscard]] rpl::producer> historyChanged() const; void sendHistoryChangeNotifications(); using MegagroupParticipant = std::tuple< @@ -99,23 +99,23 @@ public: void removeMegagroupParticipant( not_null channel, not_null user); - rpl::producer megagroupParticipantRemoved() const; - rpl::producer> megagroupParticipantRemoved( + [[nodiscard]] rpl::producer megagroupParticipantRemoved() const; + [[nodiscard]] rpl::producer> megagroupParticipantRemoved( not_null channel) const; void addNewMegagroupParticipant( not_null channel, not_null user); - rpl::producer megagroupParticipantAdded() const; - rpl::producer> megagroupParticipantAdded( + [[nodiscard]] rpl::producer megagroupParticipantAdded() const; + [[nodiscard]] rpl::producer> megagroupParticipantAdded( not_null channel) const; void notifyFeedUpdated(not_null feed, FeedUpdateFlag update); - rpl::producer feedUpdated() const; + [[nodiscard]] rpl::producer feedUpdated() const; void notifyStickersUpdated(); - rpl::producer<> stickersUpdated() const; + [[nodiscard]] rpl::producer<> stickersUpdated() const; void notifySavedGifsUpdated(); - rpl::producer<> savedGifsUpdated() const; + [[nodiscard]] rpl::producer<> savedGifsUpdated() const; bool stickersUpdateNeeded(TimeMs now) const { return stickersUpdateNeeded(_lastStickersUpdate, now); @@ -153,7 +153,7 @@ public: void setFeaturedStickerSetsUnreadCount(int count) { _featuredStickerSetsUnreadCount = count; } - rpl::producer featuredStickerSetsUnreadCountValue() const { + [[nodiscard]] rpl::producer featuredStickerSetsUnreadCountValue() const { return _featuredStickerSetsUnreadCount.value(); } const Stickers::Sets &stickerSets() const {