Show cloud stickers by emoji.

This commit is contained in:
John Preston 2018-03-07 16:53:12 +03:00
parent c3ff5f2603
commit f0a95032a5
5 changed files with 120 additions and 40 deletions

View File

@ -59,6 +59,7 @@ constexpr auto kFeedMessagesLimit = 50;
constexpr auto kReadFeaturedSetsTimeout = TimeMs(1000); constexpr auto kReadFeaturedSetsTimeout = TimeMs(1000);
constexpr auto kFileLoaderQueueStopTimeout = TimeMs(5000); constexpr auto kFileLoaderQueueStopTimeout = TimeMs(5000);
constexpr auto kFeedReadTimeout = TimeMs(1000); constexpr auto kFeedReadTimeout = TimeMs(1000);
constexpr auto kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000);
bool IsSilentPost(not_null<HistoryItem*> item, bool silent) { bool IsSilentPost(not_null<HistoryItem*> item, bool silent) {
const auto history = item->history(); const auto history = item->history();
@ -2199,11 +2200,60 @@ void ApiWrap::updateStickers() {
void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) { void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) {
Expects(megagroup->mgInfo != nullptr); Expects(megagroup->mgInfo != nullptr);
megagroup->mgInfo->stickerSet = set; megagroup->mgInfo->stickerSet = set;
request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send(); request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send();
_session->data().notifyStickersUpdated(); _session->data().notifyStickersUpdated();
} }
std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
not_null<EmojiPtr> 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) { void ApiWrap::requestStickers(TimeId now) {
if (!_session->data().stickersUpdateNeeded(now) if (!_session->data().stickersUpdateNeeded(now)
|| _stickersUpdateRequest) { || _stickersUpdateRequest) {

View File

@ -129,6 +129,8 @@ public:
void setGroupStickerSet( void setGroupStickerSet(
not_null<ChannelData*> megagroup, not_null<ChannelData*> megagroup,
const MTPInputStickerSet &set); const MTPInputStickerSet &set);
std::vector<not_null<DocumentData*>> *stickersByEmoji(
not_null<EmojiPtr> emoji);
void joinChannel(ChannelData *channel); void joinChannel(ChannelData *channel);
void leaveChannel(ChannelData *channel); void leaveChannel(ChannelData *channel);
@ -279,6 +281,12 @@ private:
using MessageDataRequests = QMap<MsgId, MessageDataRequest>; using MessageDataRequests = QMap<MsgId, MessageDataRequest>;
using SharedMediaType = Storage::SharedMediaType; using SharedMediaType = Storage::SharedMediaType;
struct StickersByEmoji {
std::vector<not_null<DocumentData*>> list;
QString hash;
TimeMs received = 0;
};
void updatesReceived(const MTPUpdates &updates); void updatesReceived(const MTPUpdates &updates);
void checkQuitPreventFinished(); void checkQuitPreventFinished();
@ -489,6 +497,8 @@ private:
base::Timer _featuredSetsReadTimer; base::Timer _featuredSetsReadTimer;
base::flat_set<uint64> _featuredSetsRead; base::flat_set<uint64> _featuredSetsRead;
base::flat_map<not_null<EmojiPtr>, StickersByEmoji> _stickersByEmoji;
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests; base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsRequestId = 0;

View File

@ -324,6 +324,7 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in
if (!isHidden()) { if (!isHidden()) {
hideAnimated(); hideAnimated();
} }
_scroll->scrollToY(0);
_mrows.clear(); _mrows.clear();
_hrows.clear(); _hrows.clear();
_brows.clear(); _brows.clear();

View File

@ -670,33 +670,52 @@ Pack GetListByEmoji(not_null<EmojiPtr> emoji) {
result = faved; result = faved;
} }
} }
auto &order = Auth().data().stickerSetsOrder(); const auto addList = [&](const Order &order, MTPDstickerSet::Flag skip) {
for (auto i = 0, l = order.size(); i != l; ++i) { for (const auto setId : order) {
auto it = sets.find(order[i]); auto it = sets.find(setId);
if (it != sets.cend()) { if (it == sets.cend() || (it->flags & skip)) {
continue;
}
if (it->emoji.isEmpty()) { if (it->emoji.isEmpty()) {
setsToRequest.insert(it->id, it->access); setsToRequest.insert(it->id, it->access);
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
} else if (!(it->flags & MTPDstickerSet::Flag::f_archived)) { continue;
auto i = it->emoji.constFind(original); }
if (i != it->emoji.cend()) { auto i = it->emoji.constFind(original);
result.reserve(result.size() + i->size()); if (i == it->emoji.cend()) {
for_const (auto sticker, *i) { continue;
if (!faved.contains(sticker)) { }
result.push_back(sticker); 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()) { if (!setsToRequest.isEmpty()) {
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
Auth().api().scheduleStickerSetRequest(i.key(), i.value()); Auth().api().scheduleStickerSetRequest(i.key(), i.value());
} }
Auth().api().requestStickerSets(); 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<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet( base::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(

View File

@ -43,13 +43,13 @@ public:
return *_session; return *_session;
} }
base::Variable<bool> &contactsLoaded() { [[nodiscard]] base::Variable<bool> &contactsLoaded() {
return _contactsLoaded; return _contactsLoaded;
} }
base::Variable<bool> &allChatsLoaded() { [[nodiscard]] base::Variable<bool> &allChatsLoaded() {
return _allChatsLoaded; return _allChatsLoaded;
} }
base::Observable<void> &moreChatsLoaded() { [[nodiscard]] base::Observable<void> &moreChatsLoaded() {
return _moreChatsLoaded; return _moreChatsLoaded;
} }
@ -57,7 +57,7 @@ public:
not_null<HistoryItem*> item; not_null<HistoryItem*> item;
not_null<bool*> isVisible; not_null<bool*> isVisible;
}; };
base::Observable<ItemVisibilityQuery> &queryItemVisibility() { [[nodiscard]] base::Observable<ItemVisibilityQuery> &queryItemVisibility() {
return _queryItemVisibility; return _queryItemVisibility;
} }
struct IdChange { struct IdChange {
@ -65,32 +65,32 @@ public:
MsgId oldId = 0; MsgId oldId = 0;
}; };
void notifyItemIdChange(IdChange event); void notifyItemIdChange(IdChange event);
rpl::producer<IdChange> itemIdChanged() const; [[nodiscard]] rpl::producer<IdChange> itemIdChanged() const;
void notifyItemLayoutChange(not_null<const HistoryItem*> item); void notifyItemLayoutChange(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const; [[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const;
void notifyViewLayoutChange(not_null<const ViewElement*> view); void notifyViewLayoutChange(not_null<const ViewElement*> view);
rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const; [[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const;
void requestItemRepaint(not_null<const HistoryItem*> item); void requestItemRepaint(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const; [[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const;
void requestViewRepaint(not_null<const ViewElement*> view); void requestViewRepaint(not_null<const ViewElement*> view);
rpl::producer<not_null<const ViewElement*>> viewRepaintRequest() const; [[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewRepaintRequest() const;
void requestItemResize(not_null<const HistoryItem*> item); void requestItemResize(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemResizeRequest() const; [[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemResizeRequest() const;
void requestViewResize(not_null<ViewElement*> view); void requestViewResize(not_null<ViewElement*> view);
rpl::producer<not_null<ViewElement*>> viewResizeRequest() const; [[nodiscard]] rpl::producer<not_null<ViewElement*>> viewResizeRequest() const;
void requestItemViewRefresh(not_null<HistoryItem*> item); void requestItemViewRefresh(not_null<HistoryItem*> item);
rpl::producer<not_null<HistoryItem*>> itemViewRefreshRequest() const; [[nodiscard]] rpl::producer<not_null<HistoryItem*>> itemViewRefreshRequest() const;
void requestAnimationPlayInline(not_null<HistoryItem*> item); void requestAnimationPlayInline(not_null<HistoryItem*> item);
rpl::producer<not_null<HistoryItem*>> animationPlayInlineRequest() const; [[nodiscard]] rpl::producer<not_null<HistoryItem*>> animationPlayInlineRequest() const;
void notifyHistoryUnloaded(not_null<const History*> history); void notifyHistoryUnloaded(not_null<const History*> history);
rpl::producer<not_null<const History*>> historyUnloaded() const; [[nodiscard]] rpl::producer<not_null<const History*>> historyUnloaded() const;
void notifyItemRemoved(not_null<const HistoryItem*> item); void notifyItemRemoved(not_null<const HistoryItem*> item);
rpl::producer<not_null<const HistoryItem*>> itemRemoved() const; [[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRemoved() const;
void notifyHistoryCleared(not_null<const History*> history); void notifyHistoryCleared(not_null<const History*> history);
rpl::producer<not_null<const History*>> historyCleared() const; [[nodiscard]] rpl::producer<not_null<const History*>> historyCleared() const;
void notifyHistoryChangeDelayed(not_null<History*> history); void notifyHistoryChangeDelayed(not_null<History*> history);
rpl::producer<not_null<History*>> historyChanged() const; [[nodiscard]] rpl::producer<not_null<History*>> historyChanged() const;
void sendHistoryChangeNotifications(); void sendHistoryChangeNotifications();
using MegagroupParticipant = std::tuple< using MegagroupParticipant = std::tuple<
@ -99,23 +99,23 @@ public:
void removeMegagroupParticipant( void removeMegagroupParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user); not_null<UserData*> user);
rpl::producer<MegagroupParticipant> megagroupParticipantRemoved() const; [[nodiscard]] rpl::producer<MegagroupParticipant> megagroupParticipantRemoved() const;
rpl::producer<not_null<UserData*>> megagroupParticipantRemoved( [[nodiscard]] rpl::producer<not_null<UserData*>> megagroupParticipantRemoved(
not_null<ChannelData*> channel) const; not_null<ChannelData*> channel) const;
void addNewMegagroupParticipant( void addNewMegagroupParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user); not_null<UserData*> user);
rpl::producer<MegagroupParticipant> megagroupParticipantAdded() const; [[nodiscard]] rpl::producer<MegagroupParticipant> megagroupParticipantAdded() const;
rpl::producer<not_null<UserData*>> megagroupParticipantAdded( [[nodiscard]] rpl::producer<not_null<UserData*>> megagroupParticipantAdded(
not_null<ChannelData*> channel) const; not_null<ChannelData*> channel) const;
void notifyFeedUpdated(not_null<Feed*> feed, FeedUpdateFlag update); void notifyFeedUpdated(not_null<Feed*> feed, FeedUpdateFlag update);
rpl::producer<FeedUpdate> feedUpdated() const; [[nodiscard]] rpl::producer<FeedUpdate> feedUpdated() const;
void notifyStickersUpdated(); void notifyStickersUpdated();
rpl::producer<> stickersUpdated() const; [[nodiscard]] rpl::producer<> stickersUpdated() const;
void notifySavedGifsUpdated(); void notifySavedGifsUpdated();
rpl::producer<> savedGifsUpdated() const; [[nodiscard]] rpl::producer<> savedGifsUpdated() const;
bool stickersUpdateNeeded(TimeMs now) const { bool stickersUpdateNeeded(TimeMs now) const {
return stickersUpdateNeeded(_lastStickersUpdate, now); return stickersUpdateNeeded(_lastStickersUpdate, now);
@ -153,7 +153,7 @@ public:
void setFeaturedStickerSetsUnreadCount(int count) { void setFeaturedStickerSetsUnreadCount(int count) {
_featuredStickerSetsUnreadCount = count; _featuredStickerSetsUnreadCount = count;
} }
rpl::producer<int> featuredStickerSetsUnreadCountValue() const { [[nodiscard]] rpl::producer<int> featuredStickerSetsUnreadCountValue() const {
return _featuredStickerSetsUnreadCount.value(); return _featuredStickerSetsUnreadCount.value();
} }
const Stickers::Sets &stickerSets() const { const Stickers::Sets &stickerSets() const {