mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 13:17:08 +02:00
Request correct saved/default reaction tags.
This commit is contained in:
parent
9b43d204e2
commit
9aacff8b54
5 changed files with 227 additions and 14 deletions
|
@ -2508,6 +2508,10 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
session().data().reactions().refreshRecentDelayed();
|
||||
} break;
|
||||
|
||||
case mtpc_updateSavedReactionTags: {
|
||||
session().data().reactions().refreshMyTagsDelayed();
|
||||
} break;
|
||||
|
||||
////// Cloud saved GIFs
|
||||
case mtpc_updateSavedGifs: {
|
||||
session().data().stickers().setLastSavedGifsUpdate(0);
|
||||
|
|
|
@ -38,6 +38,7 @@ constexpr auto kPollEach = 20 * crl::time(1000);
|
|||
constexpr auto kSizeForDownscale = 64;
|
||||
constexpr auto kRecentRequestTimeout = 10 * crl::time(1000);
|
||||
constexpr auto kRecentReactionsLimit = 40;
|
||||
constexpr auto kMyTagsRequestTimeout = crl::time(1000);
|
||||
constexpr auto kTopRequestDelay = 60 * crl::time(1000);
|
||||
constexpr auto kTopReactionsLimit = 14;
|
||||
|
||||
|
@ -64,6 +65,27 @@ constexpr auto kTopReactionsLimit = 14;
|
|||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<MyTagInfo> ListFromMTP(
|
||||
const MTPDmessages_savedReactionTags &data) {
|
||||
const auto &list = data.vtags().v;
|
||||
auto result = std::vector<MyTagInfo>();
|
||||
result.reserve(list.size());
|
||||
for (const auto &reaction : list) {
|
||||
const auto &data = reaction.data();
|
||||
const auto id = ReactionFromMTP(data.vreaction());
|
||||
if (id.empty()) {
|
||||
LOG(("API Error: reactionEmpty in messages.reactions."));
|
||||
} else {
|
||||
result.push_back({
|
||||
.id = id,
|
||||
.title = qs(data.vtitle().value_or_empty()),
|
||||
.count = data.vcount().v,
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] Reaction CustomReaction(not_null<DocumentData*> document) {
|
||||
return Reaction{
|
||||
.id = { { document->id } },
|
||||
|
@ -121,6 +143,8 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
|||
const auto &full = reactions->list(Reactions::Type::Active);
|
||||
const auto &top = reactions->list(Reactions::Type::Top);
|
||||
const auto &recent = reactions->list(Reactions::Type::Recent);
|
||||
const auto &myTags = reactions->list(Reactions::Type::MyTags);
|
||||
const auto &tags = reactions->list(Reactions::Type::Tags);
|
||||
const auto &all = item->reactions();
|
||||
const auto limit = UniqueReactionsLimit(peer);
|
||||
const auto premiumPossible = session->premiumPossible();
|
||||
|
@ -143,7 +167,19 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
|||
}
|
||||
};
|
||||
reactions->clearTemporary();
|
||||
if (limited) {
|
||||
if (item->reactionsAreTags()) {
|
||||
auto &&all = ranges::views::concat(myTags, tags);
|
||||
result.recent.reserve(myTags.size() + tags.size());
|
||||
for (const auto &reaction : all) {
|
||||
if (premiumPossible
|
||||
|| ranges::contains(tags, reaction.id, &Reaction::id)) {
|
||||
if (added.emplace(reaction.id).second) {
|
||||
result.recent.push_back(&reaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.customAllowed = premiumPossible;
|
||||
} else if (limited) {
|
||||
result.recent.reserve(all.size());
|
||||
add([&](const Reaction &reaction) {
|
||||
return ranges::contains(all, reaction.id, &MessageReaction::id);
|
||||
|
@ -193,12 +229,14 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
|||
result.customAllowed = (allowed.type == AllowedReactionsType::All)
|
||||
&& premiumPossible;
|
||||
}
|
||||
const auto i = ranges::find(
|
||||
result.recent,
|
||||
reactions->favoriteId(),
|
||||
&Reaction::id);
|
||||
if (i != end(result.recent) && i != begin(result.recent)) {
|
||||
std::rotate(begin(result.recent), i, i + 1);
|
||||
if (!item->reactionsAreTags()) {
|
||||
const auto i = ranges::find(
|
||||
result.recent,
|
||||
reactions->favoriteId(),
|
||||
&Reaction::id);
|
||||
if (i != end(result.recent) && i != begin(result.recent)) {
|
||||
std::rotate(begin(result.recent), i, i + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -280,16 +318,42 @@ void Reactions::refreshDefault() {
|
|||
requestDefault();
|
||||
}
|
||||
|
||||
void Reactions::refreshMyTags() {
|
||||
requestMyTags();
|
||||
}
|
||||
|
||||
void Reactions::refreshMyTagsDelayed() {
|
||||
if (_myTagsRequestId || _myTagsRequestScheduled) {
|
||||
return;
|
||||
}
|
||||
_myTagsRequestScheduled = true;
|
||||
base::call_delayed(kMyTagsRequestTimeout, &_owner->session(), [=] {
|
||||
if (_myTagsRequestScheduled) {
|
||||
requestMyTags();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Reactions::refreshTags() {
|
||||
requestTags();
|
||||
}
|
||||
|
||||
const std::vector<Reaction> &Reactions::list(Type type) const {
|
||||
switch (type) {
|
||||
case Type::Active: return _active;
|
||||
case Type::Recent: return _recent;
|
||||
case Type::Top: return _top;
|
||||
case Type::All: return _available;
|
||||
case Type::MyTags: return _myTags;
|
||||
case Type::Tags: return _tags;
|
||||
}
|
||||
Unexpected("Type in Reactions::list.");
|
||||
}
|
||||
|
||||
const std::vector<MyTagInfo> &Reactions::myTagsInfo() const {
|
||||
return _myTagsInfo;
|
||||
}
|
||||
|
||||
ReactionId Reactions::favoriteId() const {
|
||||
return _favoriteId;
|
||||
}
|
||||
|
@ -375,6 +439,14 @@ rpl::producer<> Reactions::favoriteUpdates() const {
|
|||
return _favoriteUpdated.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Reactions::myTagsUpdates() const {
|
||||
return _myTagsUpdated.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Reactions::tagsUpdates() const {
|
||||
return _tagsUpdated.events();
|
||||
}
|
||||
|
||||
void Reactions::preloadImageFor(const ReactionId &id) {
|
||||
if (_images.contains(id) || id.emoji().isEmpty()) {
|
||||
return;
|
||||
|
@ -617,6 +689,46 @@ void Reactions::requestGeneric() {
|
|||
}).send();
|
||||
}
|
||||
|
||||
void Reactions::requestMyTags() {
|
||||
if (_myTagsRequestId) {
|
||||
return;
|
||||
}
|
||||
auto &api = _owner->session().api();
|
||||
_myTagsRequestScheduled = false;
|
||||
_myTagsRequestId = api.request(MTPmessages_GetSavedReactionTags(
|
||||
MTP_long(_myTagsHash)
|
||||
)).done([=](const MTPmessages_SavedReactionTags &result) {
|
||||
_myTagsRequestId = 0;
|
||||
result.match([&](const MTPDmessages_savedReactionTags &data) {
|
||||
updateMyTags(data);
|
||||
}, [](const MTPDmessages_savedReactionTagsNotModified&) {
|
||||
});
|
||||
}).fail([=] {
|
||||
_myTagsRequestId = 0;
|
||||
_myTagsHash = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Reactions::requestTags() {
|
||||
if (_tagsRequestId) {
|
||||
return;
|
||||
}
|
||||
auto &api = _owner->session().api();
|
||||
_tagsRequestId = api.request(MTPmessages_GetDefaultTagReactions(
|
||||
MTP_long(_tagsHash)
|
||||
)).done([=](const MTPmessages_Reactions &result) {
|
||||
_tagsRequestId = 0;
|
||||
result.match([&](const MTPDmessages_reactions &data) {
|
||||
updateTags(data);
|
||||
}, [](const MTPDmessages_reactionsNotModified&) {
|
||||
});
|
||||
}).fail([=] {
|
||||
_tagsRequestId = 0;
|
||||
_tagsHash = 0;
|
||||
}).send();
|
||||
|
||||
}
|
||||
|
||||
void Reactions::updateTop(const MTPDmessages_reactions &data) {
|
||||
_topHash = data.vhash().v;
|
||||
_topIds = ListFromMTP(data);
|
||||
|
@ -685,6 +797,23 @@ void Reactions::updateGeneric(const MTPDmessages_stickerSet &data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Reactions::updateMyTags(const MTPDmessages_savedReactionTags &data) {
|
||||
_myTagsHash = data.vhash().v;
|
||||
_myTagsInfo = ListFromMTP(data);
|
||||
_myTagsIds = _myTagsInfo | ranges::views::transform(
|
||||
&MyTagInfo::id
|
||||
) | ranges::to_vector;
|
||||
_myTags = resolveByIds(_myTagsIds, _unresolvedMyTags);
|
||||
_myTagsUpdated.fire({});
|
||||
}
|
||||
|
||||
void Reactions::updateTags(const MTPDmessages_reactions &data) {
|
||||
_tagsHash = data.vhash().v;
|
||||
_tagsIds = ListFromMTP(data);
|
||||
_tags = resolveByIds(_tagsIds, _unresolvedTags);
|
||||
_tagsUpdated.fire({});
|
||||
}
|
||||
|
||||
void Reactions::recentUpdated() {
|
||||
_topRefreshTimer.callOnce(kTopRequestDelay);
|
||||
_recentUpdated.fire({});
|
||||
|
@ -696,9 +825,25 @@ void Reactions::defaultUpdated() {
|
|||
if (_genericAnimations.empty()) {
|
||||
requestGeneric();
|
||||
}
|
||||
refreshMyTags();
|
||||
refreshTags();
|
||||
_defaultUpdated.fire({});
|
||||
}
|
||||
|
||||
void Reactions::myTagsUpdated() {
|
||||
if (_genericAnimations.empty()) {
|
||||
requestGeneric();
|
||||
}
|
||||
_myTagsUpdated.fire({});
|
||||
}
|
||||
|
||||
void Reactions::tagsUpdated() {
|
||||
if (_genericAnimations.empty()) {
|
||||
requestGeneric();
|
||||
}
|
||||
_tagsUpdated.fire({});
|
||||
}
|
||||
|
||||
not_null<CustomEmojiManager::Listener*> Reactions::resolveListener() {
|
||||
return static_cast<CustomEmojiManager::Listener*>(this);
|
||||
}
|
||||
|
@ -710,6 +855,10 @@ void Reactions::customEmojiResolveDone(not_null<DocumentData*> document) {
|
|||
const auto top = (i != end(_unresolvedTop));
|
||||
const auto j = _unresolvedRecent.find(id);
|
||||
const auto recent = (j != end(_unresolvedRecent));
|
||||
const auto k = _unresolvedMyTags.find(id);
|
||||
const auto myTag = (k != end(_unresolvedMyTags));
|
||||
const auto l = _unresolvedTags.find(id);
|
||||
const auto tag = (l != end(_unresolvedTags));
|
||||
if (favorite) {
|
||||
_unresolvedFavoriteId = ReactionId();
|
||||
_favorite = resolveById(_favoriteId);
|
||||
|
@ -722,6 +871,14 @@ void Reactions::customEmojiResolveDone(not_null<DocumentData*> document) {
|
|||
_unresolvedRecent.erase(j);
|
||||
_recent = resolveByIds(_recentIds, _unresolvedRecent);
|
||||
}
|
||||
if (myTag) {
|
||||
_unresolvedMyTags.erase(k);
|
||||
_myTags = resolveByIds(_myTagsIds, _unresolvedMyTags);
|
||||
}
|
||||
if (tag) {
|
||||
_unresolvedTags.erase(l);
|
||||
_tags = resolveByIds(_tagsIds, _unresolvedTags);
|
||||
}
|
||||
if (favorite) {
|
||||
_favoriteUpdated.fire({});
|
||||
}
|
||||
|
@ -731,6 +888,12 @@ void Reactions::customEmojiResolveDone(not_null<DocumentData*> document) {
|
|||
if (recent) {
|
||||
_recentUpdated.fire({});
|
||||
}
|
||||
if (myTag) {
|
||||
_myTagsUpdated.fire({});
|
||||
}
|
||||
if (tag) {
|
||||
_tagsUpdated.fire({});
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Reaction> Reactions::resolveById(const ReactionId &id) {
|
||||
|
|
|
@ -56,6 +56,12 @@ struct PossibleItemReactions {
|
|||
[[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions(
|
||||
not_null<HistoryItem*> item);
|
||||
|
||||
struct MyTagInfo {
|
||||
ReactionId id;
|
||||
QString title;
|
||||
int count = 0;
|
||||
};
|
||||
|
||||
class Reactions final : private CustomEmojiManager::Listener {
|
||||
public:
|
||||
explicit Reactions(not_null<Session*> owner);
|
||||
|
@ -70,14 +76,20 @@ public:
|
|||
void refreshRecent();
|
||||
void refreshRecentDelayed();
|
||||
void refreshDefault();
|
||||
void refreshMyTags();
|
||||
void refreshMyTagsDelayed();
|
||||
void refreshTags();
|
||||
|
||||
enum class Type {
|
||||
Active,
|
||||
Recent,
|
||||
Top,
|
||||
All,
|
||||
MyTags,
|
||||
Tags,
|
||||
};
|
||||
[[nodiscard]] const std::vector<Reaction> &list(Type type) const;
|
||||
[[nodiscard]] const std::vector<MyTagInfo> &myTagsInfo() const;
|
||||
[[nodiscard]] ReactionId favoriteId() const;
|
||||
[[nodiscard]] const Reaction *favorite() const;
|
||||
void setFavorite(const ReactionId &id);
|
||||
|
@ -88,6 +100,8 @@ public:
|
|||
[[nodiscard]] rpl::producer<> recentUpdates() const;
|
||||
[[nodiscard]] rpl::producer<> defaultUpdates() const;
|
||||
[[nodiscard]] rpl::producer<> favoriteUpdates() const;
|
||||
[[nodiscard]] rpl::producer<> myTagsUpdates() const;
|
||||
[[nodiscard]] rpl::producer<> tagsUpdates() const;
|
||||
|
||||
enum class ImageSize {
|
||||
BottomInfo,
|
||||
|
@ -130,14 +144,20 @@ private:
|
|||
void requestRecent();
|
||||
void requestDefault();
|
||||
void requestGeneric();
|
||||
void requestMyTags();
|
||||
void requestTags();
|
||||
|
||||
void updateTop(const MTPDmessages_reactions &data);
|
||||
void updateRecent(const MTPDmessages_reactions &data);
|
||||
void updateDefault(const MTPDmessages_availableReactions &data);
|
||||
void updateGeneric(const MTPDmessages_stickerSet &data);
|
||||
void updateMyTags(const MTPDmessages_savedReactionTags &data);
|
||||
void updateTags(const MTPDmessages_reactions &data);
|
||||
|
||||
void recentUpdated();
|
||||
void defaultUpdated();
|
||||
void myTagsUpdated();
|
||||
void tagsUpdated();
|
||||
|
||||
[[nodiscard]] std::optional<Reaction> resolveById(const ReactionId &id);
|
||||
[[nodiscard]] std::vector<Reaction> resolveByIds(
|
||||
|
@ -167,6 +187,13 @@ private:
|
|||
std::vector<Reaction> _recent;
|
||||
std::vector<ReactionId> _recentIds;
|
||||
base::flat_set<ReactionId> _unresolvedRecent;
|
||||
std::vector<Reaction> _myTags;
|
||||
std::vector<ReactionId> _myTagsIds;
|
||||
std::vector<MyTagInfo> _myTagsInfo;
|
||||
base::flat_set<ReactionId> _unresolvedMyTags;
|
||||
std::vector<Reaction> _tags;
|
||||
std::vector<ReactionId> _tagsIds;
|
||||
base::flat_set<ReactionId> _unresolvedTags;
|
||||
std::vector<Reaction> _top;
|
||||
std::vector<ReactionId> _topIds;
|
||||
base::flat_set<ReactionId> _unresolvedTop;
|
||||
|
@ -184,6 +211,8 @@ private:
|
|||
rpl::event_stream<> _recentUpdated;
|
||||
rpl::event_stream<> _defaultUpdated;
|
||||
rpl::event_stream<> _favoriteUpdated;
|
||||
rpl::event_stream<> _myTagsUpdated;
|
||||
rpl::event_stream<> _tagsUpdated;
|
||||
|
||||
// We need &i->second stay valid while inserting new items.
|
||||
// So we use std::map instead of base::flat_map here.
|
||||
|
@ -203,6 +232,13 @@ private:
|
|||
|
||||
mtpRequestId _genericRequestId = 0;
|
||||
|
||||
mtpRequestId _myTagsRequestId = 0;
|
||||
bool _myTagsRequestScheduled = false;
|
||||
uint64 _myTagsHash = 0;
|
||||
|
||||
mtpRequestId _tagsRequestId = 0;
|
||||
uint64 _tagsHash = 0;
|
||||
|
||||
base::flat_map<ReactionId, ImageSet> _images;
|
||||
rpl::lifetime _imagesLoadLifetime;
|
||||
bool _waitingForList = false;
|
||||
|
|
|
@ -895,7 +895,9 @@ void SetupManagerList(
|
|||
reactions.topUpdates(),
|
||||
reactions.recentUpdates(),
|
||||
reactions.defaultUpdates(),
|
||||
reactions.favoriteUpdates()
|
||||
reactions.favoriteUpdates(),
|
||||
reactions.myTagsUpdates(),
|
||||
reactions.tagsUpdates()
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!state->timer.isActive()) {
|
||||
state->timer.callOnce(kRefreshListDelay);
|
||||
|
|
|
@ -529,14 +529,22 @@ bool ShowReactPremiumError(
|
|||
|| ranges::contains(item->chosenReactions(), id)
|
||||
|| item->history()->peer->isBroadcast()) {
|
||||
return false;
|
||||
}
|
||||
const auto &list = controller->session().data().reactions().list(
|
||||
Data::Reactions::Type::Active);
|
||||
const auto i = ranges::find(list, id, &Data::Reaction::id);
|
||||
if (i == end(list) || !i->premium) {
|
||||
if (!id.custom()) {
|
||||
} else if (item->reactionsAreTags()) {
|
||||
const auto &list = controller->session().data().reactions().list(
|
||||
Data::Reactions::Type::Tags);
|
||||
const auto i = ranges::find(list, id, &Data::Reaction::id);
|
||||
if (i != end(list)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const auto &list = controller->session().data().reactions().list(
|
||||
Data::Reactions::Type::Active);
|
||||
const auto i = ranges::find(list, id, &Data::Reaction::id);
|
||||
if (i == end(list) || !i->premium) {
|
||||
if (!id.custom()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ShowPremiumPreviewBox(controller, PremiumPreview::InfiniteReactions);
|
||||
return true;
|
||||
|
|
Loading…
Add table
Reference in a new issue