diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 8f028883c..d67d771fb 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -2387,6 +2387,14 @@ void Updates::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updateRecentEmojiStatuses: { + // #TODO emoji_status + } break; + + case mtpc_updateRecentReactions: { + session().data().reactions().refreshRecentDelayed(); + } break; + ////// Cloud saved GIFs case mtpc_updateSavedGifs: { session().data().stickers().setLastSavedGifsUpdate(0); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp index fe47eb4e4..9a091b4c0 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp @@ -174,7 +174,7 @@ void SaveAllowedReactions( }).fail([=](const MTP::Error &error) { if (error.type() == qstr("REACTION_INVALID")) { peer->updateFullForced(); - peer->owner().reactions().refresh(); + peer->owner().reactions().refreshDefault(); } }).send(); } diff --git a/Telegram/SourceFiles/boxes/reactions_settings_box.cpp b/Telegram/SourceFiles/boxes/reactions_settings_box.cpp index 1f295fbdd..5a5afbd87 100644 --- a/Telegram/SourceFiles/boxes/reactions_settings_box.cpp +++ b/Telegram/SourceFiles/boxes/reactions_settings_box.cpp @@ -393,8 +393,8 @@ void ReactionsSettingsBox( const auto &reactions = controller->session().data().reactions(); const auto state = box->lifetime().make_state(); - state->selectedEmoji = v::is(reactions.favorite().data) - ? v::get(reactions.favorite().data) + state->selectedEmoji = v::is(reactions.favoriteId().data) + ? v::get(reactions.favoriteId().data) : QString(); const auto pinnedToTop = box->setPinnedToTopContent( @@ -485,7 +485,7 @@ void ReactionsSettingsBox( box->addButton(tr::lng_settings_save(), [=] { const auto &data = controller->session().data(); const auto selected = state->selectedEmoji.current(); - if (data.reactions().favorite() != Data::ReactionId{ selected }) { + if (data.reactions().favoriteId() != Data::ReactionId{ selected }) { data.reactions().setFavorite(Data::ReactionId{ selected }); } box->closeBox(); diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 51077b23a..9b8edc701 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/image/image_location_factory.h" #include "mtproto/mtproto_config.h" #include "base/timer_rpl.h" +#include "base/call_delayed.h" #include "apiwrap.h" #include "styles/style_chat.h" @@ -34,6 +35,10 @@ namespace { constexpr auto kRefreshFullListEach = 60 * 60 * crl::time(1000); constexpr auto kPollEach = 20 * crl::time(1000); constexpr auto kSizeForDownscale = 64; +constexpr auto kRecentRequestTimeout = 10 * crl::time(1000); +constexpr auto kRecentReactionsLimit = 40; +constexpr auto kTopRequestDelay = 60 * crl::time(1000); +constexpr auto kTopReactionsLimit = 10; [[nodiscard]] QString ReactionIdToLog(const ReactionId &id) { if (const auto custom = id.custom()) { @@ -42,6 +47,22 @@ constexpr auto kSizeForDownscale = 64; return id.emoji(); } +[[nodiscard]] std::vector ListFromMTP( + const MTPDmessages_reactions &data) { + const auto &list = data.vreactions().v; + auto result = std::vector(); + result.reserve(list.size()); + for (const auto &reaction : list) { + const auto id = ReactionFromMTP(reaction); + if (id.empty()) { + LOG(("API Error: reactionEmpty in messages.reactions.")); + } else { + result.push_back(id); + } + } + return result; +} + } // namespace PossibleItemReactions LookupPossibleReactions(not_null item) { @@ -96,7 +117,7 @@ PossibleItemReactions LookupPossibleReactions(not_null item) { } const auto i = ranges::find( result.recent, - reactions->favorite(), + reactions->favoriteId(), &Reaction::id); if (i != end(result.recent) && i != begin(result.recent)) { std::rotate(begin(result.recent), i, i + 1); @@ -106,13 +127,14 @@ PossibleItemReactions LookupPossibleReactions(not_null item) { Reactions::Reactions(not_null owner) : _owner(owner) +, _topRefreshTimer([=] { refreshTop(); }) , _repaintTimer([=] { repaintCollected(); }) { - refresh(); + refreshDefault(); base::timer_each( kRefreshFullListEach ) | rpl::start_with_next([=] { - refresh(); + refreshDefault(); }, _lifetime); _owner->session().changes().messageUpdates( @@ -132,56 +154,102 @@ Reactions::Reactions(not_null owner) ? ReactionId{ DocumentId(config.reactionDefaultCustom) } : ReactionId{ config.reactionDefaultEmoji }; }) | rpl::filter([=](const ReactionId &id) { - return (_favorite != id) && !_saveFaveRequestId; + return !_saveFaveRequestId; }) | rpl::start_with_next([=](ReactionId &&id) { - _favorite = std::move(id); - _updated.fire({}); + applyFavorite(id); }, _lifetime); } Reactions::~Reactions() = default; -void Reactions::refresh() { - request(); +void Reactions::refreshTop() { + requestTop(); +} + +void Reactions::refreshRecent() { + requestRecent(); +} + +void Reactions::refreshRecentDelayed() { + if (_recentRequestId || _recentRequestScheduled) { + return; + } + _recentRequestScheduled = true; + base::call_delayed(kRecentRequestTimeout, &_owner->session(), [=] { + if (_recentRequestScheduled) { + requestRecent(); + } + }); +} + +void Reactions::refreshDefault() { + requestDefault(); } const std::vector &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; } Unexpected("Type in Reactions::list."); } -ReactionId Reactions::favorite() const { - return _favorite; +ReactionId Reactions::favoriteId() const { + return _favoriteId; } -void Reactions::setFavorite(const ReactionId &emoji) { +const Reaction *Reactions::favorite() const { + return _favorite ? &*_favorite : nullptr; +} + +void Reactions::setFavorite(const ReactionId &id) { const auto api = &_owner->session().api(); if (_saveFaveRequestId) { api->request(_saveFaveRequestId).cancel(); } _saveFaveRequestId = api->request(MTPmessages_SetDefaultReaction( - ReactionToMTP(emoji) + ReactionToMTP(id) )).done([=] { _saveFaveRequestId = 0; }).fail([=] { _saveFaveRequestId = 0; }).send(); - if (_favorite != emoji) { - _favorite = emoji; - _updated.fire({}); + applyFavorite(id); +} + +void Reactions::applyFavorite(const ReactionId &id) { + if (_favoriteId != id) { + _favoriteId = id; + _favorite = resolveById(_favoriteId); + if (!_favorite && _unresolvedFavoriteId != _favoriteId) { + _unresolvedFavoriteId = _favoriteId; + resolve(_favoriteId); + } + _favoriteUpdated.fire({}); } } -rpl::producer<> Reactions::updates() const { - return _updated.events(); +rpl::producer<> Reactions::topUpdates() const { + return _topUpdated.events(); +} + +rpl::producer<> Reactions::recentUpdates() const { + return _recentUpdated.events(); +} + +rpl::producer<> Reactions::defaultUpdates() const { + return _defaultUpdated.events(); +} + +rpl::producer<> Reactions::favoriteUpdates() const { + return _favoriteUpdated.events(); } void Reactions::preloadImageFor(const ReactionId &id) { - if (_images.contains(id)) { + if (_images.contains(id) || id.emoji().isEmpty()) { return; } auto &set = _images.emplace(id).first->second; @@ -195,7 +263,7 @@ void Reactions::preloadImageFor(const ReactionId &id) { loadImage(set, document, !i->centerIcon); } else if (!_waitingForList) { _waitingForList = true; - refresh(); + refreshRecent(); } } @@ -265,16 +333,6 @@ QImage Reactions::resolveImageFor( Unexpected("ImageSize in Reactions::resolveImageFor."); } -std::unique_ptr Reactions::resolveCustomFor( - const ReactionId &emoji, - ImageSize size) { - const auto custom = std::get_if(&emoji.data); - if (!custom) { - return nullptr; - } - return _owner->customEmojiManager().create(*custom, [] {}); -} - void Reactions::resolveImages() { for (auto &[id, set] : _images) { if (!set.bottomInfo.isNull() || set.icon || set.media) { @@ -343,27 +401,83 @@ void Reactions::downloadTaskFinished() { } } -void Reactions::request() { - auto &api = _owner->session().api(); - if (_requestId) { +void Reactions::requestTop() { + if (_topRequestId) { return; } - _requestId = api.request(MTPmessages_GetAvailableReactions( - MTP_int(_hash) - )).done([=](const MTPmessages_AvailableReactions &result) { - _requestId = 0; - result.match([&](const MTPDmessages_availableReactions &data) { - updateFromData(data); - }, [&](const MTPDmessages_availableReactionsNotModified &) { + auto &api = _owner->session().api(); + _topRefreshTimer.cancel(); + _topRequestId = api.request(MTPmessages_GetTopReactions( + MTP_int(kTopReactionsLimit), + MTP_long(_topHash) + )).done([=](const MTPmessages_Reactions &result) { + _topRequestId = 0; + result.match([&](const MTPDmessages_reactions &data) { + updateTop(data); + }, [](const MTPDmessages_reactionsNotModified&) { }); }).fail([=] { - _requestId = 0; - _hash = 0; + _topRequestId = 0; + _topHash = 0; }).send(); } -void Reactions::updateFromData(const MTPDmessages_availableReactions &data) { - _hash = data.vhash().v; +void Reactions::requestRecent() { + if (_recentRequestId) { + return; + } + auto &api = _owner->session().api(); + _recentRequestScheduled = false; + _recentRequestId = api.request(MTPmessages_GetRecentReactions( + MTP_int(kRecentReactionsLimit), + MTP_long(_recentHash) + )).done([=](const MTPmessages_Reactions &result) { + _recentRequestId = 0; + result.match([&](const MTPDmessages_reactions &data) { + updateRecent(data); + }, [](const MTPDmessages_reactionsNotModified&) { + }); + }).fail([=] { + _recentRequestId = 0; + _recentHash = 0; + }).send(); +} + +void Reactions::requestDefault() { + if (_defaultRequestId) { + return; + } + auto &api = _owner->session().api(); + _defaultRequestId = api.request(MTPmessages_GetAvailableReactions( + MTP_int(_defaultHash) + )).done([=](const MTPmessages_AvailableReactions &result) { + _defaultRequestId = 0; + result.match([&](const MTPDmessages_availableReactions &data) { + updateDefault(data); + }, [&](const MTPDmessages_availableReactionsNotModified &) { + }); + }).fail([=] { + _defaultRequestId = 0; + _defaultHash = 0; + }).send(); +} + +void Reactions::updateTop(const MTPDmessages_reactions &data) { + _topHash = data.vhash().v; + _topIds = ListFromMTP(data); + _top = resolveByIds(_topIds, _unresolvedTop); + _topUpdated.fire({}); +} + +void Reactions::updateRecent(const MTPDmessages_reactions &data) { + _recentHash = data.vhash().v; + _recentIds = ListFromMTP(data); + _recent = resolveByIds(_recentIds, _unresolvedRecent); + recentUpdated(); +} + +void Reactions::updateDefault(const MTPDmessages_availableReactions &data) { + _defaultHash = data.vhash().v; const auto &list = data.vreactions().v; const auto oldCache = base::take(_iconsCache); @@ -393,7 +507,99 @@ void Reactions::updateFromData(const MTPDmessages_availableReactions &data) { _waitingForList = false; resolveImages(); } - _updated.fire({}); + defaultUpdated(); +} + +void Reactions::recentUpdated() { + _topRefreshTimer.callOnce(kTopRequestDelay); + _recentUpdated.fire({}); +} + +void Reactions::defaultUpdated() { + refreshTop(); + refreshRecent(); + _defaultUpdated.fire({}); +} + +not_null Reactions::resolveListener() { + return static_cast(this); +} + +void Reactions::customEmojiResolveDone(not_null document) { + const auto id = ReactionId{ { document->id } }; + const auto favorite = (_unresolvedFavoriteId == id); + const auto i = _unresolvedTop.find(id); + const auto top = (i != end(_unresolvedTop)); + const auto j = _unresolvedRecent.find(id); + const auto recent = (j != end(_unresolvedRecent)); + if (favorite) { + _unresolvedFavoriteId = ReactionId(); + _favorite = resolveById(_favoriteId); + } + if (top) { + _unresolvedTop.erase(i); + _top = resolveByIds(_topIds, _unresolvedTop); + } + if (recent) { + _unresolvedRecent.erase(j); + _recent = resolveByIds(_recentIds, _unresolvedRecent); + } + if (favorite) { + _favoriteUpdated.fire({}); + } + if (top) { + _topUpdated.fire({}); + } + if (recent) { + _recentUpdated.fire({}); + } +} + +std::optional Reactions::resolveById(const ReactionId &id) { + if (const auto emoji = id.emoji(); !emoji.isEmpty()) { + const auto i = ranges::find(_available, id, &Reaction::id); + if (i != end(_available)) { + return *i; + } + } else if (const auto customId = id.custom()) { + const auto document = _owner->document(customId); + if (document->sticker()) { + return Reaction{ + .id = id, + .title = "Custom reaction", + .appearAnimation = document, + .selectAnimation = document, + .centerIcon = document, + .active = true, + }; + } + } + return {}; +} + +std::vector Reactions::resolveByIds( + const std::vector &ids, + base::flat_set &unresolved) { + auto result = std::vector(); + result.reserve(ids.size()); + for (const auto &id : ids) { + if (const auto resolved = resolveById(id)) { + result.push_back(*resolved); + } else if (unresolved.emplace(id).second) { + resolve(id); + } + } + return result; +} + +void Reactions::resolve(const ReactionId &id) { + if (const auto emoji = id.emoji(); !emoji.isEmpty()) { + refreshDefault(); + } else if (const auto customId = id.custom()) { + _owner->customEmojiManager().resolve( + customId, + resolveListener()); + } } std::optional Reactions::parse(const MTPAvailableReaction &entry) { @@ -409,7 +615,7 @@ std::optional Reactions::parse(const MTPAvailableReaction &entry) { ? std::make_optional(Reaction{ .id = ReactionId{ emoji }, .title = qs(data.vtitle()), - .staticIcon = _owner->processDocument(data.vstatic_icon()), + //.staticIcon = _owner->processDocument(data.vstatic_icon()), .appearAnimation = _owner->processDocument( data.vappear_animation()), .selectAnimation = selectAnimation, diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index b17701e19..d5d00493a 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" #include "data/data_message_reaction_id.h" +#include "data/stickers/data_custom_emoji.h" namespace Ui::Text { class CustomEmoji; @@ -26,7 +27,7 @@ class Session; struct Reaction { ReactionId id; QString title; - not_null staticIcon; + //not_null staticIcon; not_null appearAnimation; not_null selectAnimation; //not_null activateAnimation; @@ -46,22 +47,31 @@ struct PossibleItemReactions { [[nodiscard]] PossibleItemReactions LookupPossibleReactions( not_null item); -class Reactions final { +class Reactions final : private CustomEmojiManager::Listener { public: explicit Reactions(not_null owner); ~Reactions(); - void refresh(); + void refreshTop(); + void refreshRecent(); + void refreshRecentDelayed(); + void refreshDefault(); enum class Type { Active, + Recent, + Top, All, }; [[nodiscard]] const std::vector &list(Type type) const; - [[nodiscard]] ReactionId favorite() const; - void setFavorite(const ReactionId &emoji); + [[nodiscard]] ReactionId favoriteId() const; + [[nodiscard]] const Reaction *favorite() const; + void setFavorite(const ReactionId &id); - [[nodiscard]] rpl::producer<> updates() const; + [[nodiscard]] rpl::producer<> topUpdates() const; + [[nodiscard]] rpl::producer<> recentUpdates() const; + [[nodiscard]] rpl::producer<> defaultUpdates() const; + [[nodiscard]] rpl::producer<> favoriteUpdates() const; enum class ImageSize { BottomInfo, @@ -72,9 +82,6 @@ public: [[nodiscard]] QImage resolveImageFor( const ReactionId &emoji, ImageSize size); - [[nodiscard]] std::unique_ptr resolveCustomFor( - const ReactionId &emoji, - ImageSize size); void send(not_null item, const ReactionId &chosen); [[nodiscard]] bool sending(not_null item) const; @@ -97,8 +104,26 @@ private: bool fromAppearAnimation = false; }; - void request(); - void updateFromData(const MTPDmessages_availableReactions &data); + [[nodiscard]] not_null resolveListener(); + void customEmojiResolveDone(not_null document) override; + + void requestTop(); + void requestRecent(); + void requestDefault(); + + void updateTop(const MTPDmessages_reactions &data); + void updateRecent(const MTPDmessages_reactions &data); + void updateDefault(const MTPDmessages_availableReactions &data); + + void recentUpdated(); + void defaultUpdated(); + + [[nodiscard]] std::optional resolveById(const ReactionId &id); + [[nodiscard]] std::vector resolveByIds( + const std::vector &ids, + base::flat_set &unresolved); + void resolve(const ReactionId &id); + void applyFavorite(const ReactionId &id); [[nodiscard]] std::optional parse( const MTPAvailableReaction &entry); @@ -118,14 +143,34 @@ private: std::vector _active; std::vector _available; - ReactionId _favorite; + std::vector _recent; + std::vector _recentIds; + base::flat_set _unresolvedRecent; + std::vector _top; + std::vector _topIds; + base::flat_set _unresolvedTop; + ReactionId _favoriteId; + ReactionId _unresolvedFavoriteId; + std::optional _favorite; base::flat_map< not_null, std::shared_ptr> _iconsCache; - rpl::event_stream<> _updated; + rpl::event_stream<> _topUpdated; + rpl::event_stream<> _recentUpdated; + rpl::event_stream<> _defaultUpdated; + rpl::event_stream<> _favoriteUpdated; - mtpRequestId _requestId = 0; - int32 _hash = 0; + base::Timer _topRefreshTimer; + mtpRequestId _topRequestId = 0; + bool _topRequestScheduled = false; + uint64 _topHash = 0; + + mtpRequestId _recentRequestId = 0; + bool _recentRequestScheduled = false; + uint64 _recentHash = 0; + + mtpRequestId _defaultRequestId = 0; + int32 _defaultHash = 0; base::flat_map _images; rpl::lifetime _imagesLoadLifetime; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 57c5a11b0..f744617f9 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1941,7 +1941,7 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { void HistoryInner::toggleFavoriteReaction(not_null view) const { const auto item = view->data(); - const auto favorite = session().data().reactions().favorite(); + const auto favorite = session().data().reactions().favoriteId(); if (!ranges::contains( Data::LookupPossibleReactions(item).recent, favorite, @@ -1972,7 +1972,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { && _reactionsManager->showContextMenu( this, e, - session().data().reactions().favorite())) { + session().data().reactions().favoriteId())) { return; } auto selectedState = getSelectionState(); diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 36b4ccc62..fccc53f60 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -1187,7 +1187,7 @@ void ShowWhoReactedMenu( const auto reactions = &controller->session().data().reactions(); const auto &list = reactions->list( Data::Reactions::Type::Active); - const auto activeNonQuick = (id != reactions->favorite()) + const auto activeNonQuick = (id != reactions->favoriteId()) && ranges::contains(list, id, &Data::Reaction::id); const auto filler = lifetime.make_state( participantChosen, diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 5c5d9fe9a..660bd41ba 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2122,7 +2122,7 @@ void ListWidget::mouseDoubleClickEvent(QMouseEvent *e) { void ListWidget::toggleFavoriteReaction(not_null view) const { const auto item = view->data(); - const auto favorite = session().data().reactions().favorite(); + const auto favorite = session().data().reactions().favoriteId(); if (!ranges::contains( Data::LookupPossibleReactions(item).recent, favorite, @@ -2199,7 +2199,7 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { && _reactionsManager->showContextMenu( this, e, - session().data().reactions().favorite())) { + session().data().reactions().favoriteId())) { return; } const auto overItem = _overItemExact diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp index 155c286df..e1b91fb24 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp @@ -37,6 +37,7 @@ constexpr auto kButtonExpandDelay = crl::time(25); constexpr auto kButtonHideDelay = crl::time(300); constexpr auto kButtonExpandedHideDelay = crl::time(0); constexpr auto kMaxReactionsScrollAtOnce = 2; +constexpr auto kRefreshListDelay = crl::time(100); [[nodiscard]] QPoint LocalPosition(not_null e) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -840,6 +841,7 @@ void SetupManagerList( Main::Session *session = nullptr; rpl::lifetime sessionLifetime; rpl::lifetime peerLifetime; + base::Timer timer; }; const auto state = manager->lifetime().make_state(); @@ -857,10 +859,12 @@ void SetupManagerList( const auto peerChanged = (state->peer != peer); const auto sessionChanged = (state->session != session); const auto push = [=] { + state->timer.cancel(); if (const auto item = state->item) { manager->applyList(Data::LookupPossibleReactions(item)); } }; + state->timer.setCallback(push); if (sessionChanged) { state->sessionLifetime.destroy(); state->session = session; @@ -875,6 +879,7 @@ void SetupManagerList( ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { if (update.item == state->item) { state->item = nullptr; + state->timer.cancel(); } }, state->sessionLifetime); @@ -883,8 +888,17 @@ void SetupManagerList( return (item == state->item); }) | rpl::start_with_next(push, state->sessionLifetime); - session->data().reactions().updates( - ) | rpl::start_with_next(push, state->sessionLifetime); + const auto &reactions = session->data().reactions(); + rpl::merge( + reactions.topUpdates(), + reactions.recentUpdates(), + reactions.defaultUpdates(), + reactions.favoriteUpdates() + ) | rpl::start_with_next([=] { + if (!state->timer.isActive()) { + state->timer.callOnce(kRefreshListDelay); + } + }, state->sessionLifetime); } if (peerChanged) { state->peer = peer; diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index 07e6f1c48..2f8a152e9 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -449,7 +449,7 @@ rpl::producer FullReactionsCountValue( not_null session) { const auto reactions = &session->data().reactions(); return rpl::single(rpl::empty) | rpl::then( - reactions->updates() + reactions->defaultUpdates() ) | rpl::map([=] { return int(reactions->list(Data::Reactions::Type::Active).size()); }) | rpl::distinct_until_changed(); diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 425278e31..041971517 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -906,10 +906,10 @@ void SetupMessages( const auto &reactions = controller->session().data().reactions(); auto idValue = rpl::single( - reactions.favorite() + reactions.favoriteId() ) | rpl::then( - reactions.updates() | rpl::map([=] { - return controller->session().data().reactions().favorite(); + reactions.favoriteUpdates() | rpl::map([=] { + return controller->session().data().reactions().favoriteId(); }) ) | rpl::filter([](const Data::ReactionId &id) { return !id.empty();