diff --git a/Telegram/SourceFiles/data/components/recent_peers.cpp b/Telegram/SourceFiles/data/components/recent_peers.cpp index 32fc0ad42..1c1957873 100644 --- a/Telegram/SourceFiles/data/components/recent_peers.cpp +++ b/Telegram/SourceFiles/data/components/recent_peers.cpp @@ -7,7 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/components/recent_peers.h" +#include "main/main_session.h" +#include "storage/serialize_common.h" +#include "storage/serialize_peer.h" +#include "storage/storage_account.h" + namespace Data { +namespace { + +constexpr auto kLimit = 48; + +} // namespace RecentPeers::RecentPeers(not_null session) : _session(session) { @@ -15,4 +25,98 @@ RecentPeers::RecentPeers(not_null session) RecentPeers::~RecentPeers() = default; +const std::vector> &RecentPeers::list() const { + _session->local().readSearchSuggestions(); + + return _list; +} + +rpl::producer<> RecentPeers::updates() const { + return _updates.events(); +} + +void RecentPeers::remove(not_null peer) { + const auto i = ranges::find(_list, peer); + if (i != end(_list)) { + _list.erase(i); + _updates.fire({}); + } + _session->local().writeSearchSuggestionsDelayed(); +} + +void RecentPeers::bump(not_null peer) { + _session->local().readSearchSuggestions(); + + if (!_list.empty() && _list.front() == peer) { + return; + } + auto i = ranges::find(_list, peer); + if (i == end(_list)) { + _list.push_back(peer); + i = end(_list) - 1; + } + ranges::rotate(begin(_list), i, i + 1); + _updates.fire({}); + + _session->local().writeSearchSuggestionsDelayed(); +} + +void RecentPeers::clear() { + _session->local().readSearchSuggestions(); + + _list.clear(); + _updates.fire({}); + + _session->local().writeSearchSuggestionsDelayed(); +} + +QByteArray RecentPeers::serialize() const { + _session->local().readSearchSuggestions(); + + if (_list.empty()) { + return {}; + } + auto size = 2 * sizeof(quint32); // AppVersion, count + const auto count = std::min(int(_list.size()), kLimit); + auto &&list = _list | ranges::views::take(count); + for (const auto &peer : list) { + size += Serialize::peerSize(peer); + } + auto stream = Serialize::ByteArrayWriter(size); + stream + << quint32(AppVersion) + << quint32(_list.size()); + for (const auto &peer : list) { + Serialize::writePeer(stream, peer); + } + return std::move(stream).result(); +} + +void RecentPeers::applyLocal(QByteArray serialized) { + _list.clear(); + if (serialized.isEmpty()) { + return; + } + auto stream = Serialize::ByteArrayReader(serialized); + auto streamAppVersion = quint32(); + auto count = quint32(); + stream >> streamAppVersion >> count; + if (!stream.ok()) { + return; + } + _list.reserve(count); + for (auto i = 0; i != int(count); ++i) { + const auto peer = Serialize::readPeer( + _session, + streamAppVersion, + stream); + if (stream.ok() && peer) { + _list.push_back(peer); + } else { + _list.clear(); + return; + } + } +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/components/recent_peers.h b/Telegram/SourceFiles/data/components/recent_peers.h index e3a648b47..e30942720 100644 --- a/Telegram/SourceFiles/data/components/recent_peers.h +++ b/Telegram/SourceFiles/data/components/recent_peers.h @@ -18,9 +18,22 @@ public: explicit RecentPeers(not_null session); ~RecentPeers(); + [[nodiscard]] const std::vector> &list() const; + [[nodiscard]] rpl::producer<> updates() const; + + void remove(not_null peer); + void bump(not_null peer); + void clear(); + + [[nodiscard]] QByteArray serialize() const; + void applyLocal(QByteArray serialized); + private: const not_null _session; + std::vector> _list; + rpl::event_stream<> _updates; + }; } // namespace Data diff --git a/Telegram/SourceFiles/data/components/top_peers.cpp b/Telegram/SourceFiles/data/components/top_peers.cpp index 8a06b427b..03f4416f8 100644 --- a/Telegram/SourceFiles/data/components/top_peers.cpp +++ b/Telegram/SourceFiles/data/components/top_peers.cpp @@ -243,7 +243,12 @@ QByteArray TopPeers::serialize() const { } void TopPeers::applyLocal(QByteArray serialized) { - if (_lastReceived || serialized.isEmpty()) { + if (_lastReceived) { + return; + } + _list.clear(); + _disabled = false; + if (serialized.isEmpty()) { return; } auto stream = Serialize::ByteArrayReader(serialized); diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index 6796179bd..22484f65b 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "core/core_settings.h" #include "core/file_location.h" +#include "data/components/recent_peers.h" #include "data/components/top_peers.h" #include "data/stickers/data_stickers.h" #include "data/data_session.h" @@ -2881,7 +2882,7 @@ void Account::writeSearchSuggestions() { Expects(_owner->sessionExists()); const auto top = _owner->session().topPeers().serialize(); - const auto recent = QByteArray();// _owner->session().recentPeers().serialize(); + const auto recent = _owner->session().recentPeers().serialize(); if (top.isEmpty() && recent.isEmpty()) { if (_searchSuggestionsKey) { ClearKey(_searchSuggestionsKey, _basePath); @@ -2925,7 +2926,7 @@ void Account::readSearchSuggestions() { suggestions.stream >> top >> recent; if (CheckStreamStatus(suggestions.stream)) { _owner->session().topPeers().applyLocal(top); - //_owner->session().recentPeers().applyLocal(recent); + _owner->session().recentPeers().applyLocal(recent); } }