mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Cache topPeers locally.
This commit is contained in:
parent
c11f4efc5c
commit
4cdd939028
9 changed files with 280 additions and 14 deletions
|
@ -95,9 +95,6 @@ SettingsProxy::SettingsProxy()
|
|||
}
|
||||
|
||||
QByteArray SettingsProxy::serialize() const {
|
||||
auto result = QByteArray();
|
||||
auto stream = QDataStream(&result, QIODevice::WriteOnly);
|
||||
|
||||
const auto serializedSelected = SerializeProxyData(_selected);
|
||||
const auto serializedList = ranges::views::all(
|
||||
_list
|
||||
|
@ -111,9 +108,7 @@ QByteArray SettingsProxy::serialize() const {
|
|||
0,
|
||||
ranges::plus(),
|
||||
&Serialize::bytearraySize);
|
||||
result.reserve(size);
|
||||
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
auto stream = Serialize::ByteArrayWriter(size);
|
||||
stream
|
||||
<< qint32(_tryIPv6 ? 1 : 0)
|
||||
<< qint32(_useProxyForCalls ? 1 : 0)
|
||||
|
@ -123,9 +118,7 @@ QByteArray SettingsProxy::serialize() const {
|
|||
for (const auto &i : serializedList) {
|
||||
stream << i;
|
||||
}
|
||||
|
||||
stream.device()->close();
|
||||
return result;
|
||||
return std::move(stream).result();
|
||||
}
|
||||
|
||||
bool SettingsProxy::setFromSerialized(const QByteArray &serialized) {
|
||||
|
@ -133,7 +126,7 @@ bool SettingsProxy::setFromSerialized(const QByteArray &serialized) {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto stream = QDataStream(serialized);
|
||||
auto stream = Serialize::ByteArrayReader(serialized);
|
||||
|
||||
auto tryIPv6 = qint32(_tryIPv6 ? 1 : 0);
|
||||
auto useProxyForCalls = qint32(_useProxyForCalls ? 1 : 0);
|
||||
|
@ -148,7 +141,7 @@ bool SettingsProxy::setFromSerialized(const QByteArray &serialized) {
|
|||
>> settings
|
||||
>> selectedProxy
|
||||
>> listCount;
|
||||
if (stream.status() == QDataStream::Ok) {
|
||||
if (stream.ok()) {
|
||||
for (auto i = 0; i != listCount; ++i) {
|
||||
QByteArray data;
|
||||
stream >> data;
|
||||
|
@ -157,7 +150,7 @@ bool SettingsProxy::setFromSerialized(const QByteArray &serialized) {
|
|||
}
|
||||
}
|
||||
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
if (!stream.ok()) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::SettingsProxy::setFromSerialized()"));
|
||||
return false;
|
||||
|
|
|
@ -14,6 +14,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "storage/serialize_peer.h"
|
||||
#include "storage/storage_account.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
@ -25,6 +28,19 @@ constexpr auto kRequestTimeLimit = 10 * crl::time(1000);
|
|||
return std::exp((now - was) * 1. / decay);
|
||||
}
|
||||
|
||||
[[nodiscard]] quint64 SerializeRating(float64 rating) {
|
||||
return quint64(
|
||||
base::SafeRound(std::clamp(rating, 0., 1'000'000.) * 1'000'000.));
|
||||
}
|
||||
|
||||
[[nodiscard]] float64 DeserializeRating(quint64 rating) {
|
||||
return std::clamp(
|
||||
rating,
|
||||
quint64(),
|
||||
quint64(1'000'000'000'000ULL)
|
||||
) / 1'000'000.;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TopPeers::TopPeers(not_null<Main::Session*> session)
|
||||
|
@ -43,12 +59,16 @@ TopPeers::TopPeers(not_null<Main::Session*> session)
|
|||
TopPeers::~TopPeers() = default;
|
||||
|
||||
std::vector<not_null<PeerData*>> TopPeers::list() const {
|
||||
_session->local().readSearchSuggestions();
|
||||
|
||||
return _list
|
||||
| ranges::view::transform(&TopPeer::peer)
|
||||
| ranges::to_vector;
|
||||
}
|
||||
|
||||
bool TopPeers::disabled() const {
|
||||
_session->local().readSearchSuggestions();
|
||||
|
||||
return _disabled;
|
||||
}
|
||||
|
||||
|
@ -67,9 +87,13 @@ void TopPeers::remove(not_null<PeerData*> peer) {
|
|||
MTP_topPeerCategoryCorrespondents(),
|
||||
peer->input
|
||||
)).send();
|
||||
|
||||
_session->local().writeSearchSuggestionsDelayed();
|
||||
}
|
||||
|
||||
void TopPeers::increment(not_null<PeerData*> peer, TimeId date) {
|
||||
_session->local().readSearchSuggestions();
|
||||
|
||||
if (_disabled || date <= _lastReceivedDate) {
|
||||
return;
|
||||
}
|
||||
|
@ -95,6 +119,8 @@ void TopPeers::increment(not_null<PeerData*> peer, TimeId date) {
|
|||
if (changed) {
|
||||
_updates.fire({});
|
||||
}
|
||||
|
||||
_session->local().writeSearchSuggestionsDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +134,8 @@ void TopPeers::reload() {
|
|||
}
|
||||
|
||||
void TopPeers::toggleDisabled(bool disabled) {
|
||||
_session->local().readSearchSuggestions();
|
||||
|
||||
if (disabled) {
|
||||
if (!_disabled || !_list.empty()) {
|
||||
_disabled = true;
|
||||
|
@ -126,6 +154,8 @@ void TopPeers::toggleDisabled(bool disabled) {
|
|||
request();
|
||||
}
|
||||
}).send();
|
||||
|
||||
_session->local().writeSearchSuggestionsDelayed();
|
||||
}
|
||||
|
||||
void TopPeers::request() {
|
||||
|
@ -182,10 +212,67 @@ void TopPeers::request() {
|
|||
uint64 TopPeers::countHash() const {
|
||||
using namespace Api;
|
||||
auto hash = HashInit();
|
||||
for (const auto &top : _list) {
|
||||
for (const auto &top : _list | ranges::views::take(kLimit)) {
|
||||
HashUpdate(hash, peerToUser(top.peer->id).bare);
|
||||
}
|
||||
return HashFinalize(hash);
|
||||
}
|
||||
|
||||
QByteArray TopPeers::serialize() const {
|
||||
_session->local().readSearchSuggestions();
|
||||
|
||||
if (!_disabled && _list.empty()) {
|
||||
return {};
|
||||
}
|
||||
auto size = 3 * sizeof(quint32); // AppVersion, disabled, count
|
||||
const auto count = std::min(int(_list.size()), kLimit);
|
||||
auto &&list = _list | ranges::views::take(count);
|
||||
for (const auto &top : list) {
|
||||
size += Serialize::peerSize(top.peer) + sizeof(quint64);
|
||||
}
|
||||
auto stream = Serialize::ByteArrayWriter(size);
|
||||
stream
|
||||
<< quint32(AppVersion)
|
||||
<< quint32(_disabled ? 1 : 0)
|
||||
<< quint32(_list.size());
|
||||
for (const auto &top : list) {
|
||||
Serialize::writePeer(stream, top.peer);
|
||||
stream << SerializeRating(top.rating);
|
||||
}
|
||||
return std::move(stream).result();
|
||||
}
|
||||
|
||||
void TopPeers::applyLocal(QByteArray serialized) {
|
||||
if (_lastReceived || serialized.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto stream = Serialize::ByteArrayReader(serialized);
|
||||
auto streamAppVersion = quint32();
|
||||
auto disabled = quint32();
|
||||
auto count = quint32();
|
||||
stream >> streamAppVersion >> disabled >> count;
|
||||
if (!stream.ok()) {
|
||||
return;
|
||||
}
|
||||
_list.reserve(count);
|
||||
for (auto i = 0; i != int(count); ++i) {
|
||||
auto rating = quint64();
|
||||
const auto peer = Serialize::readPeer(
|
||||
_session,
|
||||
streamAppVersion,
|
||||
stream);
|
||||
stream >> rating;
|
||||
if (stream.ok() && peer) {
|
||||
_list.push_back({
|
||||
.peer = peer,
|
||||
.rating = DeserializeRating(rating),
|
||||
});
|
||||
} else {
|
||||
_list.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
_disabled = (disabled == 1);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -27,6 +27,9 @@ public:
|
|||
void reload();
|
||||
void toggleDisabled(bool disabled);
|
||||
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
void applyLocal(QByteArray serialized);
|
||||
|
||||
private:
|
||||
struct TopPeer {
|
||||
not_null<PeerData*> peer;
|
||||
|
|
|
@ -53,6 +53,7 @@ Account::Account(not_null<Domain*> domain, const QString &dataName, int index)
|
|||
Account::~Account() {
|
||||
if (const auto session = maybeSession()) {
|
||||
session->saveSettingsNowIfNeeded();
|
||||
_local->writeSearchSuggestionsIfNeeded();
|
||||
}
|
||||
destroySession(DestroyReason::Quitting);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Serialize {
|
||||
|
||||
ByteArrayWriter::ByteArrayWriter(int expectedSize)
|
||||
: _stream(&_result, QIODevice::WriteOnly) {
|
||||
if (expectedSize) {
|
||||
_result.reserve(expectedSize);
|
||||
}
|
||||
_stream.setVersion(QDataStream::Qt_5_1);
|
||||
}
|
||||
|
||||
QByteArray ByteArrayWriter::result() && {
|
||||
_stream.device()->close();
|
||||
return std::move(_result);
|
||||
}
|
||||
|
||||
ByteArrayReader::ByteArrayReader(QByteArray data)
|
||||
: _data(std::move(data))
|
||||
, _stream(&_data, QIODevice::ReadOnly) {
|
||||
_stream.setVersion(QDataStream::Qt_5_1);
|
||||
}
|
||||
|
||||
void writeColor(QDataStream &stream, const QColor &color) {
|
||||
stream << (quint32(uchar(color.red()))
|
||||
| (quint32(uchar(color.green())) << 8)
|
||||
|
|
|
@ -14,6 +14,70 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Serialize {
|
||||
|
||||
class ByteArrayWriter final {
|
||||
public:
|
||||
explicit ByteArrayWriter(int expectedSize = 0);
|
||||
|
||||
[[nodiscard]] QDataStream &underlying() {
|
||||
return _stream;
|
||||
}
|
||||
[[nodiscard]] operator QDataStream &() {
|
||||
return _stream;
|
||||
}
|
||||
[[nodiscard]] QByteArray result() &&;
|
||||
|
||||
private:
|
||||
QByteArray _result;
|
||||
QDataStream _stream;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline ByteArrayWriter &operator<<(ByteArrayWriter &stream, const T &data) {
|
||||
stream.underlying() << data;
|
||||
return stream;
|
||||
}
|
||||
|
||||
class ByteArrayReader final {
|
||||
public:
|
||||
explicit ByteArrayReader(QByteArray data);
|
||||
|
||||
[[nodiscard]] QDataStream &underlying() {
|
||||
return _stream;
|
||||
}
|
||||
[[nodiscard]] operator QDataStream &() {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool atEnd() const {
|
||||
return _stream.atEnd();
|
||||
}
|
||||
[[nodiscard]] bool status() const {
|
||||
return _stream.status();
|
||||
}
|
||||
[[nodiscard]] bool ok() const {
|
||||
return _stream.status() == QDataStream::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray _data;
|
||||
QDataStream _stream;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline ByteArrayReader &operator>>(ByteArrayReader &stream, T &data) {
|
||||
if (!stream.ok()) {
|
||||
data = T();
|
||||
} else {
|
||||
stream.underlying() >> data;
|
||||
if (!stream.ok()) {
|
||||
data = T();
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline int stringSize(const QString &str) {
|
||||
return sizeof(quint32) + str.size() * sizeof(ushort);
|
||||
}
|
||||
|
|
|
@ -118,12 +118,16 @@ uint32 peerSize(not_null<PeerData*> peer) {
|
|||
+ imageLocationSize(peer->userpicLocation())
|
||||
+ sizeof(qint32); // userpic has video
|
||||
if (const auto user = peer->asUser()) {
|
||||
const auto botInlinePlaceholder = user->isBot()
|
||||
? user->botInfo->inlinePlaceholder
|
||||
: QString();
|
||||
result += stringSize(user->firstName)
|
||||
+ stringSize(user->lastName)
|
||||
+ stringSize(user->phone())
|
||||
+ stringSize(user->username())
|
||||
+ sizeof(quint64) // access
|
||||
+ sizeof(qint32) // flags
|
||||
+ stringSize(botInlinePlaceholder)
|
||||
+ sizeof(quint32) // lastseen
|
||||
+ sizeof(qint32) // contact
|
||||
+ sizeof(qint32); // botInfoVersion
|
||||
|
|
|
@ -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/top_peers.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
|
@ -42,6 +43,7 @@ using namespace details;
|
|||
using Database = Cache::Database;
|
||||
|
||||
constexpr auto kDelayedWriteTimeout = crl::time(1000);
|
||||
constexpr auto kWriteSearchSuggestionsDelay = 5 * crl::time(1000);
|
||||
|
||||
constexpr auto kStickersVersionTag = quint32(-1);
|
||||
constexpr auto kStickersSerializeVersion = 4;
|
||||
|
@ -87,6 +89,7 @@ enum { // Local Storage Keys
|
|||
lskSelfSerialized = 0x15, // serialized self
|
||||
lskMasksKeys = 0x16, // no data
|
||||
lskCustomEmojiKeys = 0x17, // no data
|
||||
lskSearchSuggestions = 0x18, // no data
|
||||
};
|
||||
|
||||
auto EmptyMessageDraftSources()
|
||||
|
@ -137,10 +140,13 @@ Account::Account(not_null<Main::Account*> owner, const QString &dataName)
|
|||
, _cacheTotalTimeLimit(Database::Settings().totalTimeLimit)
|
||||
, _cacheBigFileTotalTimeLimit(Database::Settings().totalTimeLimit)
|
||||
, _writeMapTimer([=] { writeMap(); })
|
||||
, _writeLocationsTimer([=] { writeLocations(); }) {
|
||||
, _writeLocationsTimer([=] { writeLocations(); })
|
||||
, _writeSearchSuggestionsTimer([=] { writeSearchSuggestions(); }) {
|
||||
}
|
||||
|
||||
Account::~Account() {
|
||||
Expects(!_writeSearchSuggestionsTimer.isActive());
|
||||
|
||||
if (_localKey && _mapChanged) {
|
||||
writeMap();
|
||||
}
|
||||
|
@ -209,6 +215,7 @@ base::flat_set<QString> Account::collectGoodNames() const {
|
|||
_installedCustomEmojiKey,
|
||||
_featuredCustomEmojiKey,
|
||||
_archivedCustomEmojiKey,
|
||||
_searchSuggestionsKey,
|
||||
};
|
||||
auto result = base::flat_set<QString>{
|
||||
"map0",
|
||||
|
@ -294,6 +301,7 @@ Account::ReadMapResult Account::readMapWith(
|
|||
quint64 savedGifsKey = 0;
|
||||
quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0;
|
||||
quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0;
|
||||
quint64 searchSuggestionsKey = 0;
|
||||
while (!map.stream.atEnd()) {
|
||||
quint32 keyType;
|
||||
map.stream >> keyType;
|
||||
|
@ -399,6 +407,9 @@ Account::ReadMapResult Account::readMapWith(
|
|||
>> featuredCustomEmojiKey
|
||||
>> archivedCustomEmojiKey;
|
||||
} break;
|
||||
case lskSearchSuggestions: {
|
||||
map.stream >> searchSuggestionsKey;
|
||||
} break;
|
||||
default:
|
||||
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
|
||||
return ReadMapResult::Failed;
|
||||
|
@ -434,6 +445,7 @@ Account::ReadMapResult Account::readMapWith(
|
|||
_settingsKey = userSettingsKey;
|
||||
_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
|
||||
_exportSettingsKey = exportSettingsKey;
|
||||
_searchSuggestionsKey = searchSuggestionsKey;
|
||||
_oldMapVersion = mapData.version;
|
||||
|
||||
if (_oldMapVersion < AppVersion) {
|
||||
|
@ -539,6 +551,7 @@ void Account::writeMap() {
|
|||
if (_installedCustomEmojiKey || _featuredCustomEmojiKey || _archivedCustomEmojiKey) {
|
||||
mapSize += sizeof(quint32) + 3 * sizeof(quint64);
|
||||
}
|
||||
if (_searchSuggestionsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
|
||||
EncryptedDescriptor mapData(mapSize);
|
||||
if (!self.isEmpty()) {
|
||||
|
@ -598,12 +611,18 @@ void Account::writeMap() {
|
|||
<< quint64(_featuredCustomEmojiKey)
|
||||
<< quint64(_archivedCustomEmojiKey);
|
||||
}
|
||||
if (_searchSuggestionsKey) {
|
||||
mapData.stream << quint32(lskSearchSuggestions);
|
||||
mapData.stream << quint64(_searchSuggestionsKey);
|
||||
}
|
||||
map.writeEncrypted(mapData, _localKey);
|
||||
|
||||
_mapChanged = false;
|
||||
}
|
||||
|
||||
void Account::reset() {
|
||||
_writeSearchSuggestionsTimer.cancel();
|
||||
|
||||
auto names = collectGoodNames();
|
||||
_draftsMap.clear();
|
||||
_draftCursorsMap.clear();
|
||||
|
@ -624,6 +643,7 @@ void Account::reset() {
|
|||
_archivedCustomEmojiKey = 0;
|
||||
_legacyBackgroundKeyDay = _legacyBackgroundKeyNight = 0;
|
||||
_settingsKey = _recentHashtagsAndBotsKey = _exportSettingsKey = 0;
|
||||
_searchSuggestionsKey = 0;
|
||||
_oldMapVersion = 0;
|
||||
_fileLocations.clear();
|
||||
_fileLocationPairs.clear();
|
||||
|
@ -2842,6 +2862,73 @@ Export::Settings Account::readExportSettings() {
|
|||
: Export::Settings();
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestionsDelayed() {
|
||||
Expects(_owner->sessionExists());
|
||||
|
||||
if (!_writeSearchSuggestionsTimer.isActive()) {
|
||||
_writeSearchSuggestionsTimer.callOnce(kWriteSearchSuggestionsDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestionsIfNeeded() {
|
||||
if (_writeSearchSuggestionsTimer.isActive()) {
|
||||
_writeSearchSuggestionsTimer.cancel();
|
||||
writeSearchSuggestions();
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestions() {
|
||||
Expects(_owner->sessionExists());
|
||||
|
||||
const auto top = _owner->session().topPeers().serialize();
|
||||
const auto recent = QByteArray();// _owner->session().recentPeers().serialize();
|
||||
if (top.isEmpty() && recent.isEmpty()) {
|
||||
if (_searchSuggestionsKey) {
|
||||
ClearKey(_searchSuggestionsKey, _basePath);
|
||||
_searchSuggestionsKey = 0;
|
||||
writeMapDelayed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!_searchSuggestionsKey) {
|
||||
_searchSuggestionsKey = GenerateKey(_basePath);
|
||||
writeMapQueued();
|
||||
}
|
||||
quint32 size = Serialize::bytearraySize(top)
|
||||
+ Serialize::bytearraySize(recent);
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << top << recent;
|
||||
|
||||
FileWriteDescriptor file(_searchSuggestionsKey, _basePath);
|
||||
file.writeEncrypted(data, _localKey);
|
||||
}
|
||||
|
||||
void Account::readSearchSuggestions() {
|
||||
if (_searchSuggestionsRead) {
|
||||
return;
|
||||
}
|
||||
_searchSuggestionsRead = true;
|
||||
if (!_searchSuggestionsKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileReadDescriptor suggestions;
|
||||
if (!ReadEncryptedFile(suggestions, _searchSuggestionsKey, _basePath, _localKey)) {
|
||||
ClearKey(_searchSuggestionsKey, _basePath);
|
||||
_searchSuggestionsKey = 0;
|
||||
writeMapDelayed();
|
||||
return;
|
||||
}
|
||||
|
||||
auto top = QByteArray();
|
||||
auto recent = QByteArray();
|
||||
suggestions.stream >> top >> recent;
|
||||
if (CheckStreamStatus(suggestions.stream)) {
|
||||
_owner->session().topPeers().applyLocal(top);
|
||||
//_owner->session().recentPeers().applyLocal(recent);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSelf() {
|
||||
writeMapDelayed();
|
||||
}
|
||||
|
|
|
@ -148,6 +148,11 @@ public:
|
|||
void writeExportSettings(const Export::Settings &settings);
|
||||
[[nodiscard]] Export::Settings readExportSettings();
|
||||
|
||||
void writeSearchSuggestionsDelayed();
|
||||
void writeSearchSuggestionsIfNeeded();
|
||||
void writeSearchSuggestions();
|
||||
void readSearchSuggestions();
|
||||
|
||||
void writeSelf();
|
||||
|
||||
// Read self is special, it can't get session from account, because
|
||||
|
@ -291,6 +296,7 @@ private:
|
|||
FileKey _installedCustomEmojiKey = 0;
|
||||
FileKey _featuredCustomEmojiKey = 0;
|
||||
FileKey _archivedCustomEmojiKey = 0;
|
||||
FileKey _searchSuggestionsKey = 0;
|
||||
|
||||
qint64 _cacheTotalSizeLimit = 0;
|
||||
qint64 _cacheBigFileTotalSizeLimit = 0;
|
||||
|
@ -301,11 +307,13 @@ private:
|
|||
bool _trustedBotsRead = false;
|
||||
bool _readingUserSettings = false;
|
||||
bool _recentHashtagsAndBotsWereRead = false;
|
||||
bool _searchSuggestionsRead = false;
|
||||
|
||||
int _oldMapVersion = 0;
|
||||
|
||||
base::Timer _writeMapTimer;
|
||||
base::Timer _writeLocationsTimer;
|
||||
base::Timer _writeSearchSuggestionsTimer;
|
||||
bool _mapChanged = false;
|
||||
bool _locationsChanged = false;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue