diff --git a/android/app/src/main/cpp/app/organicmaps/bookmarks/data/BookmarkManager.cpp b/android/app/src/main/cpp/app/organicmaps/bookmarks/data/BookmarkManager.cpp index bf237a4382..f801f37b51 100644 --- a/android/app/src/main/cpp/app/organicmaps/bookmarks/data/BookmarkManager.cpp +++ b/android/app/src/main/cpp/app/organicmaps/bookmarks/data/BookmarkManager.cpp @@ -591,6 +591,15 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetAllCategoriesVisibi frm()->GetBookmarkManager().SetAllCategoriesVisibility(static_cast(visible)); } +JNIEXPORT void JNICALL +Java_app_organicmaps_bookmarks_data_BookmarkManager_nativePrepareTrackFileForSharing(JNIEnv * env, jclass, jlong trackId, jint kmlFileType) +{ + frm()->GetBookmarkManager().PrepareTrackFileForSharing(static_cast(trackId), [env](BookmarkManager::SharingResult const & result) + { + OnPreparedFileForSharing(env, result); + }, static_cast(kmlFileType)); +} + JNIEXPORT void JNICALL Java_app_organicmaps_bookmarks_data_BookmarkManager_nativePrepareFileForSharing(JNIEnv * env, jclass, jlongArray catIds, jint kmlFileType) { diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksListFragment.java b/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksListFragment.java index 19fda9e02a..b7aa7a2fc2 100644 --- a/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksListFragment.java +++ b/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksListFragment.java @@ -795,10 +795,17 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment items = new ArrayList<>(); items.add(new MenuBottomSheetItem(R.string.edit, R.drawable.ic_edit, this::onTrackEditActionSelected)); + items.add(new MenuBottomSheetItem(R.string.export_file, R.drawable.ic_file_kmz, () -> onShareTrackSelected(track.getTrackId(), KmlFileType.Text))); + items.add(new MenuBottomSheetItem(R.string.export_file_gpx, R.drawable.ic_file_gpx, () -> onShareTrackSelected(track.getTrackId(), KmlFileType.Gpx))); items.add(new MenuBottomSheetItem(R.string.delete, R.drawable.ic_delete, () -> onDeleteTrackSelected(track.getTrackId()))); return items; } + private void onShareTrackSelected(long trackId, KmlFileType kmlFileType) + { + BookmarksSharingHelper.INSTANCE.prepareTrackForSharing(requireActivity(), trackId, kmlFileType); + } + @Override public void onPreparedFileForSharing(@NonNull BookmarkSharingResult result) { diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksSharingHelper.java b/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksSharingHelper.java index 168b062b1c..26e9b03413 100644 --- a/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksSharingHelper.java +++ b/android/app/src/main/java/app/organicmaps/bookmarks/BookmarksSharingHelper.java @@ -36,6 +36,12 @@ public enum BookmarksSharingHelper BookmarkManager.INSTANCE.prepareCategoriesForSharing(new long[]{catId}, kmlFileType); } + public void prepareTrackForSharing(@NonNull Activity context, long trackId, KmlFileType kmlFileType) + { + showProgressDialog(context); + BookmarkManager.INSTANCE.prepareTrackForSharing(trackId, kmlFileType); + } + private void showProgressDialog(@NonNull Activity context) { mProgressDialog = new ProgressDialog(context, R.style.MwmTheme_ProgressDialog); diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java b/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java index c30bfdd7b7..a7015715da 100644 --- a/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java +++ b/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java @@ -527,6 +527,11 @@ public enum BookmarkManager nativePrepareFileForSharing(catIds, kmlFileType.ordinal()); } + public void prepareTrackForSharing(long trackId, KmlFileType kmlFileType) + { + nativePrepareTrackFileForSharing(trackId, kmlFileType.ordinal()); + } + public void setNotificationsEnabled(boolean enabled) { nativeSetNotificationsEnabled(enabled); @@ -806,6 +811,8 @@ public enum BookmarkManager private static native void nativePrepareFileForSharing(long[] catIds, int kmlFileType); + private static native void nativePrepareTrackFileForSharing(long trackId, int kmlFileType); + private static native boolean nativeIsCategoryEmpty(long catId); private static native void nativeSetNotificationsEnabled(boolean enabled); diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 58e2bad73c..5446b59378 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -2901,6 +2901,24 @@ bool BookmarkManager::SaveBookmarkCategory(kml::MarkGroupId groupId, Writer & wr return SaveKmlData(*kmlData, writer, fileType); } + +BookmarkManager::KMLDataCollectionPtr BookmarkManager::PrepareToSaveBookmarksForTrack(kml::TrackId trackId) +{ + CHECK_THREAD_CHECKER(m_threadChecker, ()); + auto collection = std::make_shared(); + auto const & track = GetTrack(trackId); + auto const & categoryData = new kml::CategoryData(); + auto name = kml::LocalizableString(); + kml::SetDefaultStr(name, track->GetName()); + categoryData->m_name = name; + auto const & trackData = track->GetData(); + auto const & fileData = new kml::FileData(); + fileData->m_categoryData = *categoryData; + fileData->m_tracksData.push_back(trackData); + collection->emplace_back("", fileData); + return collection; +} + BookmarkManager::KMLDataCollectionPtr BookmarkManager::PrepareToSaveBookmarks( kml::GroupIdCollection const & groupIdCollection) { @@ -2959,6 +2977,23 @@ void BookmarkManager::SaveBookmarks(kml::GroupIdCollection const & groupIdCollec }); } +void BookmarkManager::PrepareTrackFileForSharing(kml::TrackId trackId, SharingHandler && handler, KmlFileType kmlFileType) +{ + CHECK_THREAD_CHECKER(m_threadChecker, ()); + ASSERT(handler, ()); + auto collection = PrepareToSaveBookmarksForTrack(trackId); + if (m_testModeEnabled) + { + handler(GetFileForSharing(std::move(collection), kmlFileType)); + } + else + { + GetPlatform().RunTask(Platform::Thread::File, + [collection = std::move(collection), handler = std::move(handler), kmlFileType = kmlFileType]() mutable + { handler(GetFileForSharing(std::move(collection), kmlFileType)); }); + } +} + void BookmarkManager::PrepareFileForSharing(kml::GroupIdCollection && categoriesIds, SharingHandler && handler, KmlFileType kmlFileType) { CHECK_THREAD_CHECKER(m_threadChecker, ()); diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index b2e9adc467..3e13c01611 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -354,6 +354,7 @@ public: using SharingHandler = platform::SafeCallback; void PrepareFileForSharing(kml::GroupIdCollection && categoriesIds, SharingHandler && handler, KmlFileType kmlFileType); + void PrepareTrackFileForSharing(kml::TrackId trackId, SharingHandler && handler, KmlFileType kmlFileType); void PrepareAllFilesForSharing(SharingHandler && handler); bool AreAllCategoriesEmpty() const; @@ -649,6 +650,7 @@ private: std::unique_ptr CollectBmGroupKMLData(BookmarkCategory const * group) const; KMLDataCollectionPtr PrepareToSaveBookmarks(kml::GroupIdCollection const & groupIdCollection); + KMLDataCollectionPtr PrepareToSaveBookmarksForTrack(kml::TrackId trackId); bool HasDuplicatedIds(kml::FileData const & fileData) const; template @@ -830,6 +832,7 @@ private: Metadata m_metadata; + // Switch some operations in bookmark manager to synchronous mode to simplify unit-testing. bool m_testModeEnabled = false; CategoriesCollection m_compilations; diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp index 0107c4a5da..ab18b3eb74 100644 --- a/map/map_tests/bookmarks_test.cpp +++ b/map/map_tests/bookmarks_test.cpp @@ -1507,6 +1507,72 @@ UNIT_CLASS_TEST(Runner, ExportSingleUnicode) bmManager.PrepareFileForSharing(std::move(categories), checker, KmlFileType::Text); } +UNIT_CLASS_TEST(Runner, ExportSingleTrackKmz) +{ + std::string const file = GetPlatform().TestsDataPathForFile("test_data/gpx/export_test.gpx"); + BookmarkManager bmManager(BM_CALLBACKS); + bmManager.EnableTestMode(true); + BookmarkManager::KMLDataCollection kmlDataCollection; + kmlDataCollection.emplace_back(file, LoadKmlFile(file, KmlFileType::Gpx)); + bmManager.CreateCategories(std::move(kmlDataCollection)); + + auto const kmzChecker = [](BookmarkManager::SharingResult const & result) + { + auto filePath = result.m_sharingPath; + TEST(filePath.find("Some random route.kmz") != std::string::npos, ()); + ZipFileReader::FileList files; + ZipFileReader::FilesList(filePath, files); + std::string kmlFileName = "Some random route.kml"; + auto kmlFilePath = base::JoinPath(GetPlatform().TmpDir(), kmlFileName); + ZipFileReader::UnzipFile(filePath, kmlFileName, kmlFilePath); + auto fileData = LoadKmlFile(kmlFilePath, KmlFileType::Text); + TEST_EQUAL(1, fileData->m_tracksData.size(), ()); + TEST(base::DeleteFileX(filePath), ()); + TEST(base::DeleteFileX(kmlFilePath), ()); + }; + + auto category = bmManager.GetUnsortedBmGroupsIdList()[0]; + auto tracks = bmManager.GetTrackIds(category); + for (auto const & trackId : tracks) + { + auto track = bmManager.GetTrack(trackId); + if (track->GetName().find("Some random route") != std::string::npos) + { + bmManager.PrepareTrackFileForSharing(track->GetId(), kmzChecker, KmlFileType::Text); + } + } +} + +UNIT_CLASS_TEST(Runner, ExportSingleTrackGpx) +{ + std::string const file = GetPlatform().TestsDataPathForFile("test_data/gpx/export_test.gpx"); + BookmarkManager bmManager(BM_CALLBACKS); + bmManager.EnableTestMode(true); + BookmarkManager::KMLDataCollection kmlDataCollection; + kmlDataCollection.emplace_back(file, LoadKmlFile(file, KmlFileType::Gpx)); + bmManager.CreateCategories(std::move(kmlDataCollection)); + + auto const gpxChecker = [](BookmarkManager::SharingResult const & result) + { + auto filePath = result.m_sharingPath; + TEST(filePath.find("Some random route.gpx") != std::string::npos, ()); + auto fileData = LoadKmlFile(filePath, KmlFileType::Gpx); + TEST_EQUAL(1, fileData->m_tracksData.size(), ()); + TEST(base::DeleteFileX(filePath), ()); + }; + + auto category = bmManager.GetUnsortedBmGroupsIdList()[0]; + auto tracks = bmManager.GetTrackIds(category); + for (auto const & trackId : tracks) + { + auto track = bmManager.GetTrack(trackId); + if (track->GetName().find("Some random route") != std::string::npos) + { + bmManager.PrepareTrackFileForSharing(track->GetId(), gpxChecker, KmlFileType::Gpx); + } + } +} + UNIT_CLASS_TEST(Runner, ExportSingleGpx) { std::string const file = GetPlatform().TestsDataPathForFile("test_data/gpx/route.gpx");