diff --git a/map/CMakeLists.txt b/map/CMakeLists.txt index bc58e0a9dd..28063efbc4 100644 --- a/map/CMakeLists.txt +++ b/map/CMakeLists.txt @@ -77,6 +77,13 @@ set( local_ads_supported_types.cpp mwm_url.cpp mwm_url.hpp + notifications/notification_manager.cpp + notifications/notification_manager.hpp + notifications/notification_queue.hpp + notifications/notification_queue_serdes.cpp + notifications/notification_queue_serdes.hpp + notifications/notification_queue_storage.cpp + notifications/notification_queue_storage.hpp place_page_info.cpp place_page_info.hpp purchase.cpp diff --git a/map/framework.cpp b/map/framework.cpp index 7c09f94624..c2b405534f 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -510,6 +510,8 @@ Framework::Framework(FrameworkParams const & params) InitTransliteration(); LOG(LDEBUG, ("Transliterators initialized")); + + eye::Eye::Instance().Subscribe(&m_notificationManager); } Framework::~Framework() diff --git a/map/framework.hpp b/map/framework.hpp index 840a0edcf2..83ad4af907 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -10,6 +10,7 @@ #include "map/feature_vec_model.hpp" #include "map/local_ads_manager.hpp" #include "map/mwm_url.hpp" +#include "map/notifications/notification_manager.hpp" #include "map/place_page_info.hpp" #include "map/purchase.hpp" #include "map/routing_manager.hpp" @@ -897,6 +898,7 @@ public: private: std::unique_ptr m_purchase; TipsApi m_tipsApi; + notifications::NotificationManager m_notificationManager; public: TipsApi const & GetTipsApi() const; diff --git a/map/framework_light.hpp b/map/framework_light.hpp index dd5f746c40..c88f02e1cb 100644 --- a/map/framework_light.hpp +++ b/map/framework_light.hpp @@ -2,6 +2,7 @@ #include "map/bookmark_manager.hpp" #include "map/local_ads_manager.hpp" +#include "map/notifications/notification_manager.hpp" #include "map/user.hpp" #include "ugc/storage.hpp" @@ -31,6 +32,7 @@ enum RequestType REQUEST_TYPE_LOCATION = 1u << 4, REQUEST_TYPE_LOCAL_ADS_FEATURES = 1u << 5, REQUEST_TYPE_LOCAL_ADS_STATISTICS = 1u << 6, + REQUEST_TYPE_NOTIFICATION = 1u << 7, }; using RequestTypeMask = unsigned; @@ -90,6 +92,13 @@ public: request ^= REQUEST_TYPE_LOCAL_ADS_STATISTICS; } + if (request & REQUEST_TYPE_NOTIFICATION) + { + m_notificationManager = std::make_unique(); + m_notificationManager->Load(); + request ^= REQUEST_TYPE_NOTIFICATION; + } + CHECK_EQUAL(request, REQUEST_TYPE_EMPTY, ("Incorrect mask type:", request)); } @@ -114,6 +123,7 @@ private: std::unique_ptr m_countryInfoReader; std::unique_ptr m_localAdsFeaturesReader; std::unique_ptr m_localAdsStatistics; + std::unique_ptr m_notificationManager; }; template<> @@ -174,4 +184,10 @@ auto Framework::GetNonConst() return m_localAdsStatistics.get(); } + +template <> +auto Framework::Get() const +{ + return m_notificationManager->GetNotification(); +} } // namespace lightweight diff --git a/map/map_tests/CMakeLists.txt b/map/map_tests/CMakeLists.txt index ce114728e5..dbc90c26f8 100644 --- a/map/map_tests/CMakeLists.txt +++ b/map/map_tests/CMakeLists.txt @@ -20,6 +20,7 @@ set( gps_track_test.cpp kmz_unarchive_test.cpp mwm_url_tests.cpp + notification_tests.cpp search_api_tests.cpp tips_tests.cpp transliteration_test.cpp diff --git a/map/map_tests/notification_tests.cpp b/map/map_tests/notification_tests.cpp new file mode 100644 index 0000000000..e2c2e8dca7 --- /dev/null +++ b/map/map_tests/notification_tests.cpp @@ -0,0 +1,114 @@ +#include "testing/testing.hpp" + +#include "map/notifications/notification_queue.hpp" +#include "map/notifications/notification_queue_serdes.hpp" +#include "map/notifications/notification_queue_storage.hpp" + +#include "metrics/eye_info.hpp" + +#include "platform/platform.hpp" + +#include +#include + +using namespace notifications; + +namespace +{ +class ScopedNotificationsQueue +{ +public: + ~ScopedNotificationsQueue() + { + GetPlatform().RmDirRecursively(QueueStorage::GetNotificationsDir()); + } +}; + +Queue MakeDefaultQueueForTesting() +{ + Queue queue; + + { + Notification notification; + notification.m_type = Notification::Type::UgcReview; + + notification.m_mapObject = std::make_unique(); + notification.m_mapObject->m_bestType = "cafe"; + notification.m_mapObject->m_pos = {15.686299, 73.704084}; + notification.m_mapObject->m_readableName = "Baba"; + + queue.m_candidates.emplace_back(std::move(notification)); + } + + { + Notification notification; + notification.m_type = Notification::Type::UgcReview; + + notification.m_mapObject = std::make_unique(); + notification.m_mapObject->m_bestType = "shop"; + notification.m_mapObject->m_pos = {12.923975, 100.776627}; + notification.m_mapObject->m_readableName = "7eleven"; + + queue.m_candidates.emplace_back(std::move(notification)); + } + + { + Notification notification; + notification.m_type = Notification::Type::UgcReview; + + notification.m_mapObject = std::make_unique(); + notification.m_mapObject->m_bestType = "viewpoint"; + notification.m_mapObject->m_pos = {-45.943995, 167.619933}; + notification.m_mapObject->m_readableName = "Waiau"; + + queue.m_candidates.emplace_back(std::move(notification)); + } + + return queue; +} + +void CompareWithDefaultQueue(Queue const & lhs) +{ + auto const rhs = MakeDefaultQueueForTesting(); + + TEST_EQUAL(lhs.m_candidates.size(), rhs.m_candidates.size(), ()); + + for (size_t i = 0; i < lhs.m_candidates.size(); ++i) + { + auto const & lhsItem = lhs.m_candidates[i]; + auto const & rhsItem = rhs.m_candidates[i]; + TEST_EQUAL(lhsItem.m_type, rhsItem.m_type, ()); + TEST(lhsItem.m_mapObject, ()); + TEST_EQUAL(lhsItem.m_mapObject->m_bestType, rhsItem.m_mapObject->m_bestType, ()); + TEST_EQUAL(lhsItem.m_mapObject->m_readableName, rhsItem.m_mapObject->m_readableName, ()); + TEST_EQUAL(lhsItem.m_mapObject->m_pos, lhsItem.m_mapObject->m_pos, ()); + } +} + +UNIT_TEST(Notifications_QueueSerdesTest) +{ + auto const queue = MakeDefaultQueueForTesting(); + + std::vector queueData; + QueueSerdes::Serialize(queue, queueData); + Queue result; + QueueSerdes::Deserialize(queueData, result); + + CompareWithDefaultQueue(result); +} + +UNIT_CLASS_TEST(ScopedNotificationsQueue, Notifications_QueueSaveLoadTest) +{ + auto const queue = MakeDefaultQueueForTesting(); + + std::vector queueData; + QueueSerdes::Serialize(queue, queueData); + TEST(QueueStorage::Save(queueData), ()); + queueData.clear(); + TEST(QueueStorage::Load(queueData), ()); + Queue result; + QueueSerdes::Deserialize(queueData, result); + + CompareWithDefaultQueue(result); +} +} // namespace diff --git a/map/notifications/notification_manager.cpp b/map/notifications/notification_manager.cpp new file mode 100644 index 0000000000..6d0ada4c1e --- /dev/null +++ b/map/notifications/notification_manager.cpp @@ -0,0 +1,51 @@ +#include "map/notifications/notification_manager.hpp" +#include "map/notifications/notification_queue_serdes.hpp" +#include "map/notifications/notification_queue_storage.hpp" + +#include "base/logging.hpp" + +namespace notifications +{ +void NotificationManager::Load() +{ + std::vector queueFileData; + if (!QueueStorage::Load(queueFileData)) + { + m_queue = {}; + return; + } + + try + { + QueueSerdes::Deserialize(queueFileData, m_queue); + } + catch (QueueSerdes::UnknownVersion const & ex) + { + // Notifications queue might be empty. + m_queue = {}; + } +} + +boost::optional NotificationManager::GetNotification() const +{ + if (m_queue.m_candidates.empty()) + return {}; + + // Is not implemented yet. Coming soon. + + return {}; +} + +void NotificationManager::OnMapObjectEvent(eye::MapObject const & poi, + eye::MapObject::Events const & events) +{ + // Is not implemented yet. Coming soon. +} + +bool NotificationManager::Save() +{ + std::vector fileData; + QueueSerdes::Serialize(m_queue, fileData); + return QueueStorage::Save(fileData); +} +} // namespace notifications diff --git a/map/notifications/notification_manager.hpp b/map/notifications/notification_manager.hpp new file mode 100644 index 0000000000..92e43ab0e9 --- /dev/null +++ b/map/notifications/notification_manager.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "map/notifications/notification_queue.hpp" + +#include "metrics/eye.hpp" + +#include + +#include + +namespace notifications +{ +class NotificationManager : public eye::Subscriber +{ +public: + void Load(); + + boost::optional GetNotification() const; + + // eye::Subscriber overrides: + void OnMapObjectEvent(eye::MapObject const & poi, eye::MapObject::Events const & events) override; + +private: + bool Save(); + + // Notification candidates queue. + Queue m_queue; +}; +} // namespace notifications diff --git a/map/notifications/notification_queue.hpp b/map/notifications/notification_queue.hpp new file mode 100644 index 0000000000..38993738ba --- /dev/null +++ b/map/notifications/notification_queue.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "metrics/eye_info.hpp" + +#include +#include +#include + +namespace notifications +{ +struct Notification +{ + enum class Type : uint8_t + { + UgcAuth, + UgcReview + }; + + DECLARE_VISITOR(visitor(m_type, "type"), visitor(m_mapObject, "object")); + + Type m_type; + std::unique_ptr m_mapObject; +}; + +using Candidates = std::vector; + +enum class Version : int8_t +{ + Unknown = -1, + V0 = 0, + Latest = V0 +}; + +struct QueueV0 +{ + static Version GetVersion() { return Version::V0; } + + DECLARE_VISITOR(visitor(m_candidates, "queue")) + + Candidates m_candidates; +}; + +using Queue = QueueV0; + +inline std::string DebugPrint(Notification::Type type) +{ + switch (type) + { + case Notification::Type::UgcAuth: return "UgcAuth"; + case Notification::Type::UgcReview: return "UgcReview"; + } +} +} // namespace notifications diff --git a/map/notifications/notification_queue_serdes.cpp b/map/notifications/notification_queue_serdes.cpp new file mode 100644 index 0000000000..1d9a3c0f26 --- /dev/null +++ b/map/notifications/notification_queue_serdes.cpp @@ -0,0 +1,50 @@ +#include "map/notifications/notification_queue_serdes.hpp" + +#include "coding/reader.hpp" +#include "coding/serdes_json.hpp" +#include "coding/write_to_sink.hpp" +#include "coding/writer.hpp" + +#include "base/logging.hpp" + +namespace notifications +{ +// static +void QueueSerdes::Serialize(Queue const & queue, std::vector & result) +{ + result.clear(); + using Sink = MemWriter>; + Sink writer(result); + + WriteToSink(writer, static_cast(Queue::GetVersion())); + + coding::SerializerJson ser(writer); + ser(queue); +} + +// static +void QueueSerdes::Deserialize(std::vector const & bytes, Queue & result) +{ + MemReader reader(bytes.data(), bytes.size()); + NonOwningReaderSource source(reader); + + auto version = static_cast(Version::Unknown); + ReadPrimitiveFromSource(source, version); + if (version == static_cast(Version::V0)) + { + try + { + coding::DeserializerJson des(source); + des(result); + } + catch (base::Json::Exception & ex) + { + LOG(LERROR, ("Cannot deserialize notification queue file. Exception:", ex.Msg(), + "Version:", version, "File content:", std::string(bytes.begin(), bytes.end()))); + } + return; + } + + MYTHROW(UnknownVersion, ("Unknown data version:", static_cast(version))); +} +} // namespace notifications diff --git a/map/notifications/notification_queue_serdes.hpp b/map/notifications/notification_queue_serdes.hpp new file mode 100644 index 0000000000..072432f006 --- /dev/null +++ b/map/notifications/notification_queue_serdes.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "map/notifications/notification_queue.hpp" + +#include "base/exception.hpp" + +#include +#include + +namespace notifications +{ +class QueueSerdes +{ +public: + DECLARE_EXCEPTION(UnknownVersion, RootException); + + static void Serialize(Queue const & queue, std::vector & result); + static void Deserialize(std::vector const & bytes, Queue & result); +}; +} // namespace notifications diff --git a/map/notifications/notification_queue_storage.cpp b/map/notifications/notification_queue_storage.cpp new file mode 100644 index 0000000000..733b906d31 --- /dev/null +++ b/map/notifications/notification_queue_storage.cpp @@ -0,0 +1,72 @@ +#include "map/notifications/notification_queue_storage.hpp" + +#include "platform/platform.hpp" + +#include "coding/file_name_utils.hpp" +#include "coding/file_reader.hpp" +#include "coding/file_writer.hpp" +#include "coding/internal/file_data.hpp" + +#include "base/logging.hpp" + +namespace notifications +{ +// static +std::string QueueStorage::GetNotificationsDir() +{ + return base::JoinPath(GetPlatform().SettingsDir(), "notifications"); +} + +// static +std::string QueueStorage::GetFilePath() +{ + return base::JoinPath(GetNotificationsDir(), "queue"); +} + +// static +bool QueueStorage::Save(std::vector const & src) +{ + if (!GetPlatform().IsDirectory(GetNotificationsDir()) && + !GetPlatform().MkDirChecked(GetNotificationsDir())) + { + return false; + } + + return base::WriteToTempAndRenameToFile(GetFilePath(), [&src](string const & fileName) + { + try + { + FileWriter writer(fileName); + writer.Write(src.data(), src.size()); + } + catch (FileWriter::Exception const & ex) + { + LOG(LERROR, (ex.what(), ex.Msg())); + return false; + } + + return true; + }); +} + +// static +bool QueueStorage::Load(std::vector & dst) +{ + try + { + FileReader reader(GetFilePath()); + + dst.clear(); + dst.resize(reader.Size()); + + reader.Read(0, dst.data(), dst.size()); + } + catch (FileReader::Exception const &) + { + dst.clear(); + return false; + } + + return true; +} +} // namespace notifications diff --git a/map/notifications/notification_queue_storage.hpp b/map/notifications/notification_queue_storage.hpp new file mode 100644 index 0000000000..88b00e48f6 --- /dev/null +++ b/map/notifications/notification_queue_storage.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +namespace notifications +{ +class QueueStorage +{ +public: + static std::string GetFilePath(); + static std::string GetNotificationsDir(); + static bool Save(std::vector const & src); + static bool Load(std::vector & dst); +}; +} // namespace notifications diff --git a/metrics/eye.cpp b/metrics/eye.cpp index c91b679a54..942a4bf5e7 100644 --- a/metrics/eye.cpp +++ b/metrics/eye.cpp @@ -28,7 +28,7 @@ void Load(Info & info) std::vector infoFileData; std::vector mapObjectsFileData; - if (!Storage::LoadInfo(infoFileData) || !Storage::LoadMapObjects(mapObjectsFileData)) + if (!Storage::LoadInfo(infoFileData) && !Storage::LoadMapObjects(mapObjectsFileData)) { info = {}; return; @@ -36,8 +36,11 @@ void Load(Info & info) try { - Serdes::DeserializeInfo(infoFileData, info); - Serdes::DeserializeMapObjects(mapObjectsFileData, info.m_mapObjects); + if (!infoFileData.empty()) + Serdes::DeserializeInfo(infoFileData, info); + + if (!mapObjectsFileData.empty()) + Serdes::DeserializeMapObjects(mapObjectsFileData, info.m_mapObjects); } catch (Serdes::UnknownVersion const & ex) { diff --git a/metrics/eye_info.hpp b/metrics/eye_info.hpp index 3873e5b521..6c5e35d9ec 100644 --- a/metrics/eye_info.hpp +++ b/metrics/eye_info.hpp @@ -198,8 +198,12 @@ struct MapObject return m_pos == rhs.m_pos && m_bestType == rhs.m_bestType; } + DECLARE_VISITOR(visitor(m_bestType, "type"), visitor(m_pos, "pos"), + visitor(m_readableName, "name")); + std::string m_bestType; ms::LatLon m_pos; + std::string m_readableName; }; using MapObjects = std::unordered_map; diff --git a/metrics/eye_serdes.cpp b/metrics/eye_serdes.cpp index b46132269f..3b87c0c38f 100644 --- a/metrics/eye_serdes.cpp +++ b/metrics/eye_serdes.cpp @@ -1,5 +1,4 @@ #include "metrics/eye_serdes.hpp" -#include "metrics/eye_info.hpp" #include "coding/reader.hpp" #include "coding/serdes_json.hpp" diff --git a/metrics/eye_storage.cpp b/metrics/eye_storage.cpp index 72e4cad469..eb00b003ca 100644 --- a/metrics/eye_storage.cpp +++ b/metrics/eye_storage.cpp @@ -9,8 +9,6 @@ #include "base/logging.hpp" -#include - namespace { bool Save(std::string const & filename, std::vector const & src) diff --git a/xcode/map/map.xcodeproj/project.pbxproj b/xcode/map/map.xcodeproj/project.pbxproj index 9d02d81d38..2c9df751a1 100644 --- a/xcode/map/map.xcodeproj/project.pbxproj +++ b/xcode/map/map.xcodeproj/project.pbxproj @@ -78,6 +78,13 @@ 3DA5723120C195ED007BDE27 /* everywhere_search_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DA5722D20C195EC007BDE27 /* everywhere_search_callback.hpp */; }; 3DA5723220C195ED007BDE27 /* everywhere_search_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DA5722E20C195EC007BDE27 /* everywhere_search_callback.cpp */; }; 3DA5723320C195ED007BDE27 /* viewport_search_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DA5722F20C195EC007BDE27 /* viewport_search_callback.cpp */; }; + 3DD1166621888AAC007A2ED4 /* notification_queue_serdes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1165F21888AAC007A2ED4 /* notification_queue_serdes.cpp */; }; + 3DD1166721888AAC007A2ED4 /* notification_queue.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DD1166021888AAC007A2ED4 /* notification_queue.hpp */; }; + 3DD1166821888AAC007A2ED4 /* notification_queue_storage.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DD1166121888AAC007A2ED4 /* notification_queue_storage.hpp */; }; + 3DD1166921888AAC007A2ED4 /* notification_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1166221888AAC007A2ED4 /* notification_manager.cpp */; }; + 3DD1166A21888AAD007A2ED4 /* notification_queue_storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1166321888AAC007A2ED4 /* notification_queue_storage.cpp */; }; + 3DD1166B21888AAD007A2ED4 /* notification_manager.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DD1166421888AAC007A2ED4 /* notification_manager.hpp */; }; + 3DD1166C21888AAD007A2ED4 /* notification_queue_serdes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DD1166521888AAC007A2ED4 /* notification_queue_serdes.hpp */; }; 3DD122BB2135708900EDFB53 /* libmetrics_tests_support.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DD122BA2135708900EDFB53 /* libmetrics_tests_support.a */; }; 3DD122BD2135708900EDFB53 /* libmetrics.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DD122BC2135708900EDFB53 /* libmetrics.a */; }; 451E692921494C2700764A97 /* purchase.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 451E692721494C2600764A97 /* purchase.hpp */; }; @@ -304,6 +311,13 @@ 3DA5722D20C195EC007BDE27 /* everywhere_search_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = everywhere_search_callback.hpp; sourceTree = ""; }; 3DA5722E20C195EC007BDE27 /* everywhere_search_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = everywhere_search_callback.cpp; sourceTree = ""; }; 3DA5722F20C195EC007BDE27 /* viewport_search_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = viewport_search_callback.cpp; sourceTree = ""; }; + 3DD1165F21888AAC007A2ED4 /* notification_queue_serdes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = notification_queue_serdes.cpp; sourceTree = ""; }; + 3DD1166021888AAC007A2ED4 /* notification_queue.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = notification_queue.hpp; sourceTree = ""; }; + 3DD1166121888AAC007A2ED4 /* notification_queue_storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = notification_queue_storage.hpp; sourceTree = ""; }; + 3DD1166221888AAC007A2ED4 /* notification_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = notification_manager.cpp; sourceTree = ""; }; + 3DD1166321888AAC007A2ED4 /* notification_queue_storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = notification_queue_storage.cpp; sourceTree = ""; }; + 3DD1166421888AAC007A2ED4 /* notification_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = notification_manager.hpp; sourceTree = ""; }; + 3DD1166521888AAC007A2ED4 /* notification_queue_serdes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = notification_queue_serdes.hpp; sourceTree = ""; }; 3DD122BA2135708900EDFB53 /* libmetrics_tests_support.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmetrics_tests_support.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3DD122BC2135708900EDFB53 /* libmetrics.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmetrics.a; sourceTree = BUILT_PRODUCTS_DIR; }; 451E692721494C2600764A97 /* purchase.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = purchase.hpp; sourceTree = ""; }; @@ -623,6 +637,20 @@ path = ../../map/map_integration_tests; sourceTree = ""; }; + 3DD1165E21888AAC007A2ED4 /* notifications */ = { + isa = PBXGroup; + children = ( + 3DD1165F21888AAC007A2ED4 /* notification_queue_serdes.cpp */, + 3DD1166021888AAC007A2ED4 /* notification_queue.hpp */, + 3DD1166121888AAC007A2ED4 /* notification_queue_storage.hpp */, + 3DD1166221888AAC007A2ED4 /* notification_manager.cpp */, + 3DD1166321888AAC007A2ED4 /* notification_queue_storage.cpp */, + 3DD1166421888AAC007A2ED4 /* notification_manager.hpp */, + 3DD1166521888AAC007A2ED4 /* notification_queue_serdes.hpp */, + ); + path = notifications; + sourceTree = ""; + }; 674A29CA1B26FCC0001A525C /* map_tests */ = { isa = PBXGroup; children = ( @@ -731,6 +759,7 @@ 675345BD1A4054AD00A0A8C3 /* map */ = { isa = PBXGroup; children = ( + 3DD1165E21888AAC007A2ED4 /* notifications */, 675345CB1A4054E800A0A8C3 /* address_finder.cpp */, 45201E921CE4AC90008A4842 /* api_mark_point.cpp */, 34921F611BFA0A6900737D6E /* api_mark_point.hpp */, @@ -871,12 +900,14 @@ 45F6EE9E1FB1C77600019892 /* mwm_tree.hpp in Headers */, 6753466B1A4054E800A0A8C3 /* geourl_process.hpp in Headers */, F6B283081C1B03320081957A /* gps_track_storage.hpp in Headers */, + 3DD1166B21888AAD007A2ED4 /* notification_manager.hpp in Headers */, 3D4F44BB21345D270005E765 /* tips_api.hpp in Headers */, 675346671A4054E800A0A8C3 /* ge0_parser.hpp in Headers */, 675346A21A4054E800A0A8C3 /* user_mark.hpp in Headers */, 454649F21F2728CE00EF4064 /* local_ads_mark.hpp in Headers */, BBA014AE2073C784007402E4 /* bookmark_helpers.hpp in Headers */, F6B283061C1B03320081957A /* gps_track_filter.hpp in Headers */, + 3DD1166821888AAC007A2ED4 /* notification_queue_storage.hpp in Headers */, 3D62CBCC20F4DFD600E7BB6E /* search_product_info.hpp in Headers */, F69687C8201B4A3600457650 /* discovery_search_params.hpp in Headers */, 3D4E99831FB462B60025B48C /* viewport_search_params.hpp in Headers */, @@ -899,6 +930,7 @@ 3D4E99A51FB4A6410025B48C /* booking_filter.hpp in Headers */, 56C116612090E5670068BBC0 /* extrapolator.hpp in Headers */, 3D62CBDA20FF6C8B00E7BB6E /* discovery_search.hpp in Headers */, + 3DD1166C21888AAD007A2ED4 /* notification_queue_serdes.hpp in Headers */, 675346491A4054E800A0A8C3 /* bookmark_manager.hpp in Headers */, 3DA5714320B5CC80007BDE27 /* booking_filter_processor.hpp in Headers */, F6B2830A1C1B03320081957A /* gps_track.hpp in Headers */, @@ -906,6 +938,7 @@ F6D67CE32063F4980032FD38 /* framework_light.hpp in Headers */, 45F6EE9D1FB1C77600019892 /* search_api.hpp in Headers */, 3DA5723120C195ED007BDE27 /* everywhere_search_callback.hpp in Headers */, + 3DD1166721888AAC007A2ED4 /* notification_queue.hpp in Headers */, 3DA5723020C195ED007BDE27 /* viewport_search_callback.hpp in Headers */, F6FC3CB51FC323430001D929 /* discovery_client_params.hpp in Headers */, 0831F23C200E53600034C365 /* bookmarks_search_params.hpp in Headers */, @@ -1080,6 +1113,7 @@ 675346481A4054E800A0A8C3 /* bookmark_manager.cpp in Sources */, 45F6EE9F1FB1C77600019892 /* search_api.cpp in Sources */, BB4E5F251FCC664A00A77250 /* transit_display.cpp in Sources */, + 3DD1166A21888AAD007A2ED4 /* notification_queue_storage.cpp in Sources */, 3D47B2931F054BC5000828D2 /* taxi_delegate.cpp in Sources */, 675346741A4054E800A0A8C3 /* mwm_url.cpp in Sources */, 3DA5714220B5CC80007BDE27 /* booking_filter_processor.cpp in Sources */, @@ -1087,6 +1121,7 @@ BBFC7E3A202D29C000531BE7 /* user_mark_layer.cpp in Sources */, F6B283091C1B03320081957A /* gps_track.cpp in Sources */, 34583BCF1C88556800F94664 /* place_page_info.cpp in Sources */, + 3DD1166921888AAC007A2ED4 /* notification_manager.cpp in Sources */, F6B283031C1B03320081957A /* gps_track_collection.cpp in Sources */, 3D4E99A31FB4A6410025B48C /* booking_filter_cache.cpp in Sources */, 6753469B1A4054E800A0A8C3 /* track.cpp in Sources */, @@ -1100,6 +1135,7 @@ F63421F81DF9BF9100A96868 /* reachable_by_taxi_checker.cpp in Sources */, 56C116602090E5670068BBC0 /* extrapolator.cpp in Sources */, 6753466A1A4054E800A0A8C3 /* geourl_process.cpp in Sources */, + 3DD1166621888AAC007A2ED4 /* notification_queue_serdes.cpp in Sources */, 348AB57C1D7EE0C6009F8301 /* chart_generator.cpp in Sources */, 342D833A1D5233E8000D8AEA /* displacement_mode_manager.cpp in Sources */, 3D47B2C71F20EF06000828D2 /* displayed_categories_modifiers.cpp in Sources */,