diff --git a/drape_frontend/user_marks_global.hpp b/drape_frontend/user_marks_global.hpp index 0961b4e401..9d0d31eda8 100644 --- a/drape_frontend/user_marks_global.hpp +++ b/drape_frontend/user_marks_global.hpp @@ -6,9 +6,9 @@ namespace df { -using MarkID = uint32_t; -using LineID = uint32_t; -using MarkGroupID = uint32_t; +using MarkID = uint64_t; +using LineID = uint64_t; +using MarkGroupID = uint64_t; using MarkIDCollection = std::vector; using LineIDCollection = std::vector; using MarkIDSet = std::set>; diff --git a/iphone/Maps/Common/MWMTypes.h b/iphone/Maps/Common/MWMTypes.h index 0ad5dbbb3f..348893fdea 100644 --- a/iphone/Maps/Common/MWMTypes.h +++ b/iphone/Maps/Common/MWMTypes.h @@ -15,9 +15,9 @@ typedef NS_ENUM(NSUInteger, MWMTheme) { MWMThemeAuto }; -typedef uint32_t MWMMarkID; -typedef uint32_t MWMLineID; -typedef uint32_t MWMMarkGroupID; +typedef uint64_t MWMMarkID; +typedef uint64_t MWMLineID; +typedef uint64_t MWMMarkGroupID; typedef NSArray * MWMGroupIDCollection; typedef NS_ENUM(NSUInteger, MWMBookmarksShareStatus) { diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager+Swift.swift b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager+Swift.swift index 4287898864..a5be5d04f7 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager+Swift.swift +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager+Swift.swift @@ -1,5 +1,5 @@ extension MWMBookmarksManager { @nonobjc static func groupsIdList() -> [MWMMarkGroupID] { - return groupsIdList().map { $0.uint32Value } + return groupsIdList().map { $0.uint64Value } } } diff --git a/map/bookmark.cpp b/map/bookmark.cpp index ac7181ba69..b680aaa724 100644 --- a/map/bookmark.cpp +++ b/map/bookmark.cpp @@ -35,13 +35,16 @@ Bookmark::Bookmark(m2::PointD const & ptOrg) , m_groupId(df::kInvalidMarkGroupId) { m_data.m_point = ptOrg; + m_data.m_id = GetId(); } Bookmark::Bookmark(kml::BookmarkData const & data) - : Base(data.m_point, UserMark::BOOKMARK) + : Base(data.m_id, data.m_point, UserMark::BOOKMARK) , m_data(data) , m_groupId(df::kInvalidMarkGroupId) -{} +{ + m_data.m_id = GetId(); +} void Bookmark::SetData(kml::BookmarkData const & data) { @@ -181,6 +184,7 @@ BookmarkCategory::BookmarkCategory(std::string const & name, df::MarkGroupID gro , m_groupId(groupId) , m_autoSave(autoSave) { + m_data.m_id = groupId; SetName(name); } @@ -190,6 +194,7 @@ BookmarkCategory::BookmarkCategory(kml::CategoryData const & data, df::MarkGroup , m_autoSave(autoSave) , m_data(data) { + m_data.m_id = groupId; Base::SetIsVisible(m_data.m_visible); } diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 969bf7361e..24b61eb55d 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -43,12 +43,34 @@ using namespace std::placeholders; namespace { +std::string const kLastBookmarkCategoryId = "LastBookmarkCategoryId"; std::string const kLastBookmarkCategory = "LastBookmarkCategory"; std::string const kLastBookmarkType = "LastBookmarkType"; std::string const kLastBookmarkColor = "LastBookmarkColor"; std::string const kKmzExtension = ".kmz"; std::string const kBookmarksExt = ".kmb"; +uint64_t LoadLastBmCategoryId() +{ + uint64_t lastId; + std::string val; + if (GetPlatform().GetSecureStorage().Load(kLastBookmarkCategoryId, val) && strings::to_uint64(val, lastId)) + return lastId; + return static_cast(UserMark::BOOKMARK); +} + +void SaveLastBmCategoryId(uint64_t lastId) +{ + GetPlatform().GetSecureStorage().Save(kLastBookmarkCategoryId, strings::to_string(lastId)); +} + +uint64_t ResetLastBmCategoryId() +{ + auto const lastId = static_cast(UserMark::BOOKMARK); + SaveLastBmCategoryId(lastId); + return lastId; +} + // Returns extension with a dot in a lower case. std::string GetFileExt(std::string const & filePath) { @@ -402,13 +424,14 @@ BookmarkManager::BookmarkManager(Callbacks && callbacks) : m_callbacks(std::move(callbacks)) , m_changesTracker(*this) , m_needTeardown(false) - , m_nextGroupID(UserMark::BOOKMARK) + , m_lastGroupID(LoadLastBmCategoryId()) , m_bookmarkCloud(Cloud::CloudParams("bmc.json", "bookmarks", "BookmarkCloudParam", GetBookmarksDirectory(), std::string(kBookmarksExt), std::bind(&ConvertBeforeUploading, _1, _2), std::bind(&ConvertAfterDownloading, _1, _2))) { ASSERT(m_callbacks.m_getStringsBundle != nullptr, ()); + ASSERT_GREATER_OR_EQUAL(m_lastGroupID, UserMark::BOOKMARK, ()); m_userMarkLayers.reserve(UserMark::BOOKMARK); for (uint32_t i = 0; i < UserMark::BOOKMARK; ++i) m_userMarkLayers.emplace_back(std::make_unique(static_cast(i))); @@ -1026,9 +1049,14 @@ void BookmarkManager::NotifyAboutFinishAsyncLoading(std::shared_ptrempty()) + { CreateCategories(std::move(*collection)); + } else + { + CheckAndResetLastIds(); CheckAndCreateDefaultCategory(); + } if (m_asyncLoadingCallbacks.m_onFinished != nullptr) m_asyncLoadingCallbacks.m_onFinished(); @@ -1136,15 +1164,15 @@ df::MarkGroupID BookmarkManager::LastEditedBMCategory() { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - if (HasBmCategory(m_lastGroupId)) - return m_lastGroupId; + if (HasBmCategory(m_lastEditedGroupId)) + return m_lastEditedGroupId; for (auto & cat : m_categories) { if (cat.second->GetFileName() == m_lastCategoryUrl) { - m_lastGroupId = cat.first; - return m_lastGroupId; + m_lastEditedGroupId = cat.first; + return m_lastEditedGroupId; } } CheckAndCreateDefaultCategory(); @@ -1159,7 +1187,7 @@ kml::PredefinedColor BookmarkManager::LastEditedBMColor() const void BookmarkManager::SetLastEditedBmCategory(df::MarkGroupID groupId) { - m_lastGroupId = groupId; + m_lastEditedGroupId = groupId; m_lastCategoryUrl = GetBmCategory(groupId)->GetFileName(); SaveState(); } @@ -1237,7 +1265,13 @@ bool BookmarkManager::HasBmCategory(df::MarkGroupID groupId) const df::MarkGroupID BookmarkManager::CreateBookmarkCategory(kml::CategoryData const & data, bool autoSave) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - auto const groupId = m_nextGroupID++; + auto groupId = data.m_id; + if (groupId == kml::kInvalidCategoryId) + { + groupId = ++m_lastGroupID; + SaveLastBmCategoryId(m_lastGroupID); + } + ASSERT_EQUAL(m_categories.count(groupId), 0, ()); auto & cat = m_categories[groupId]; cat = my::make_unique(data, groupId, autoSave); m_bmGroupsIdList.push_back(groupId); @@ -1248,7 +1282,8 @@ df::MarkGroupID BookmarkManager::CreateBookmarkCategory(kml::CategoryData const df::MarkGroupID BookmarkManager::CreateBookmarkCategory(std::string const & name, bool autoSave) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - auto const groupId = m_nextGroupID++; + auto const groupId = ++m_lastGroupID; + SaveLastBmCategoryId(m_lastGroupID); auto & cat = m_categories[groupId]; cat = my::make_unique(name, groupId, autoSave); m_bmGroupsIdList.push_back(groupId); @@ -1263,6 +1298,16 @@ void BookmarkManager::CheckAndCreateDefaultCategory() CreateBookmarkCategory(m_callbacks.m_getStringsBundle().GetString("core_my_places")); } +void BookmarkManager::CheckAndResetLastIds() +{ + if (m_categories.empty()) + m_lastGroupID = ResetLastBmCategoryId(); + if (m_bookmarks.empty()) + UserMark::ResetLastId(UserMark::BOOKMARK); + if (m_tracks.empty()) + Track::ResetLastId(); +} + bool BookmarkManager::DeleteBmCategory(df::MarkGroupID groupId) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); @@ -1385,7 +1430,8 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool } else { - groupId = CreateBookmarkCategory(categoryData, false /* autoSave */); + bool const saveAfterCreation = categoryData.m_id == df::kInvalidMarkGroupId; + groupId = CreateBookmarkCategory(categoryData, saveAfterCreation); loadedGroups.insert(groupId); group = GetBmCategory(groupId); group->SetFileName(fileName); diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index 65fbb2cd08..aa633051c9 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -415,6 +415,7 @@ private: void GetBookmarksData(df::MarkIDSet const & markIds, std::vector> & data) const; void CheckAndCreateDefaultCategory(); + void CheckAndResetLastIds(); std::unique_ptr CollectBmGroupKMLData(BookmarkCategory const * group) const; void SaveToFile(kml::FileData & kmlData, Writer & writer, bool useBinary) const; @@ -434,7 +435,7 @@ private: df::DrapeEngineSafePtr m_drapeEngine; AsyncLoadingCallbacks m_asyncLoadingCallbacks; std::atomic m_needTeardown; - df::MarkGroupID m_nextGroupID; + df::MarkGroupID m_lastGroupID; size_t m_openedEditSessionsCount = 0; bool m_loadBookmarksFinished = false; bool m_firstDrapeNotification = false; @@ -445,7 +446,7 @@ private: df::GroupIDCollection m_bmGroupsIdList; std::string m_lastCategoryUrl; - df::MarkGroupID m_lastGroupId = df::kInvalidMarkGroupId; + df::MarkGroupID m_lastEditedGroupId = df::kInvalidMarkGroupId; kml::PredefinedColor m_lastColor = kml::PredefinedColor::Red; UserMarkLayers m_userMarkLayers; diff --git a/map/track.cpp b/map/track.cpp index cb054448b8..caa653edaf 100644 --- a/map/track.cpp +++ b/map/track.cpp @@ -6,25 +6,62 @@ #include "geometry/distance_on_sphere.hpp" +#include "platform/platform.hpp" + +#include "base/string_utils.hpp" + namespace { -df::LineID GetNextUserLineId() +static const std::string kLastLineId = "LastLineId"; + +uint64_t LoadLastLineId() { - static std::atomic nextLineId(0); - return static_cast(++nextLineId); + uint64_t lastId; + std::string val; + if (GetPlatform().GetSecureStorage().Load(kLastLineId, val) && strings::to_uint64(val, lastId)) + return lastId; + return 0; +} + +void SaveLastLineId(uint64_t lastId) +{ + GetPlatform().GetSecureStorage().Save(kLastLineId, strings::to_string(lastId)); +} + +df::LineID GetNextUserLineId(bool reset = false) +{ + static std::atomic lastLineId(LoadLastLineId()); + + if (reset) + { + SaveLastLineId(0); + lastLineId = 0; + return df::kInvalidLineId; + } + + auto const id = static_cast(++lastLineId); + SaveLastLineId(lastLineId); + return id; } } // namespace Track::Track(kml::TrackData const & data) - : df::UserLineMark(GetNextUserLineId()) + : df::UserLineMark(data.m_id == df::kInvalidLineId ? GetNextUserLineId() : data.m_id) , m_data(data) , m_groupID(0) { + m_data.m_id = GetId(); ASSERT_GREATER(m_data.m_points.size(), 1, ()); } -string const & Track::GetName() const +// static +void Track::ResetLastId() +{ + UNUSED_VALUE(GetNextUserLineId(true /* reset */)); +} + +string Track::GetName() const { return kml::GetDefaultStr(m_data.m_name); } diff --git a/map/track.hpp b/map/track.hpp index 7bb774fe8b..be5fb128a4 100644 --- a/map/track.hpp +++ b/map/track.hpp @@ -22,13 +22,14 @@ class Track : public df::UserLineMark public: explicit Track(kml::TrackData const & data); + static void ResetLastId(); + bool IsDirty() const override { return m_isDirty; } void ResetChanges() const override { m_isDirty = false; } kml::TrackData const & GetData() const { return m_data; } - //void SetData(kml::TrackData const & data) { m_data = data; } - string const & GetName() const; + std::string GetName() const; m2::RectD GetLimitRect() const; double GetLengthMeters() const; diff --git a/map/user_mark.cpp b/map/user_mark.cpp index dfc3bc6c63..444cb90c39 100644 --- a/map/user_mark.cpp +++ b/map/user_mark.cpp @@ -5,6 +5,8 @@ #include "geometry/mercator.hpp" +#include "platform/platform.hpp" + #include "base/string_utils.hpp" #include @@ -12,17 +14,60 @@ namespace { static const uint32_t kMarkIdTypeBitsCount = 4; +static const std::string kLastBookmarkId = "LastBookmarkId"; -df::MarkID GetNextUserMarkId(UserMark::Type type) +uint64_t LoadLastBookmarkId() { - static std::atomic nextMarkId(0); + uint64_t lastId; + std::string val; + if (GetPlatform().GetSecureStorage().Load(kLastBookmarkId, val) && strings::to_uint64(val, lastId)) + return lastId; + return 0; +} + +void SaveLastBookmarkId(uint64_t lastId) +{ + GetPlatform().GetSecureStorage().Save(kLastBookmarkId, strings::to_string(lastId)); +} + +df::MarkID GetNextUserMarkId(UserMark::Type type, bool reset = false) +{ + static std::atomic lastBookmarkId(LoadLastBookmarkId()); + static std::atomic lastUserMarkId(0); + + if (reset) + { + if (type == UserMark::Type::BOOKMARK) + { + SaveLastBookmarkId(0); + lastBookmarkId = 0; + } + return df::kInvalidMarkId; + } static_assert(UserMark::Type::BOOKMARK < (1 << kMarkIdTypeBitsCount), "Not enough bits for user mark type."); - return static_cast( - (++nextMarkId) | (type << static_cast(sizeof(df::MarkID) * 8 - kMarkIdTypeBitsCount))); + + auto const typeBits = static_cast(type) << (sizeof(df::MarkID) * 8 - kMarkIdTypeBitsCount); + if (type == UserMark::Type::BOOKMARK) + { + auto const id = static_cast((++lastBookmarkId) | typeBits); + SaveLastBookmarkId(lastBookmarkId); + return id; + } + else + { + return static_cast((++lastUserMarkId) | typeBits); + } } } // namespace +UserMark::UserMark(df::MarkID id, m2::PointD const & ptOrg, UserMark::Type type) + : df::UserPointMark(id == df::kInvalidMarkId ? GetNextUserMarkId(type) : id) + , m_ptOrg(ptOrg) +{ + ASSERT_EQUAL(GetMarkType(), type, ()); +} + UserMark::UserMark(m2::PointD const & ptOrg, UserMark::Type type) : df::UserPointMark(GetNextUserMarkId(type)) , m_ptOrg(ptOrg) @@ -34,6 +79,12 @@ UserMark::Type UserMark::GetMarkType(df::MarkID id) return static_cast(id >> (sizeof(id) * 8 - kMarkIdTypeBitsCount)); } +// static +void UserMark::ResetLastId(UserMark::Type type) +{ + UNUSED_VALUE(GetNextUserMarkId(type, true /* reset */)); +} + m2::PointD const & UserMark::GetPivot() const { return m_ptOrg; diff --git a/map/user_mark.hpp b/map/user_mark.hpp index 29ca9b3cd7..8a5fe8f439 100644 --- a/map/user_mark.hpp +++ b/map/user_mark.hpp @@ -42,9 +42,11 @@ public: BOOKMARK, // Should always be the last one }; + UserMark(df::MarkID id, m2::PointD const & ptOrg, UserMark::Type type); UserMark(m2::PointD const & ptOrg, UserMark::Type type); static Type GetMarkType(df::MarkID id); + static void ResetLastId(UserMark::Type type); Type GetMarkType() const { return GetMarkType(GetId()); } df::MarkGroupID GetGroupId() const override { return GetMarkType(); }