From fe7b5bddca3ca95b242f674bf5634eaddd3d5cdc Mon Sep 17 00:00:00 2001 From: Roman Kuznetsov Date: Sat, 24 Mar 2018 14:54:21 +0300 Subject: [PATCH] Refactored bookmark sharing as async process --- .../BMCView/BMCViewController.swift | 13 +-- .../BMCViewModel/BMCDefaultViewModel.swift | 32 +++--- .../BMCViewModel/BMCViewModel.swift | 5 +- .../Maps/Core/Bookmarks/MWMBookmarksManager.h | 4 +- .../Core/Bookmarks/MWMBookmarksManager.mm | 54 ++++++---- .../Core/Bookmarks/MWMBookmarksObserver.h | 1 + map/bookmark_manager.cpp | 100 ++++++++---------- map/bookmark_manager.hpp | 28 ++--- 8 files changed, 126 insertions(+), 111 deletions(-) diff --git a/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift b/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift index 736b3202fb..f2c3f0b621 100644 --- a/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift +++ b/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift @@ -67,7 +67,7 @@ final class BMCViewController: MWMViewController { let fileName = (url.lastPathComponent as NSString).deletingPathExtension let message = String(coreFormat: L("share_bookmarks_email_body"), arguments: [fileName]) let shareController = AVC.share(for: url, message: message) { [viewModel] _, _, _, _ in - viewModel?.endShareCategory(category: category) + viewModel?.finishShareCategory() } shareController!.present(inParentViewController: self, anchorView: anchor) } @@ -75,11 +75,12 @@ final class BMCViewController: MWMViewController { let showAlertOnError = { (title: String, text: String) in MWMAlertViewController.activeAlert().presentInfoAlert(title, text: text) } - - let shareCategoryStatus = viewModel.beginShareCategory(category: category) - switch shareCategoryStatus { - case let .success(url): shareOnSuccess(url) - case let .error(title, text): showAlertOnError(title, text) + + viewModel.shareCategory(category: category) { (status: BMCShareCategoryStatus) in + switch status { + case let .success(url): shareOnSuccess(url) + case let .error(title, text): showAlertOnError(title, text) + } } } diff --git a/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCDefaultViewModel.swift b/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCDefaultViewModel.swift index 1d99d1e117..d3ad3dbbf8 100644 --- a/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCDefaultViewModel.swift +++ b/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCDefaultViewModel.swift @@ -14,6 +14,8 @@ final class BMCDefaultViewModel: NSObject { private(set) var isPendingPermission = false private var isAuthenticated = false + + private var onPreparedToShareCategory: BMCViewModel.onPreparedToShareHandler? var minCategoryNameLength: UInt = Const.minCategoryNameLength var maxCategoryNameLength: UInt = Const.maxCategoryNameLength @@ -159,20 +161,14 @@ extension BMCDefaultViewModel: BMCViewModel { return BM.checkCategoryName(name) } - func beginShareCategory(category: BMCCategory) -> BMCShareCategoryStatus { - switch BM.beginShareCategory(category.identifier) { - case .success: - return .success(BM.shareCategoryURL()) - case .emptyCategory: - return .error(title: L("bookmarks_error_title_share_empty"), text: L("bookmarks_error_message_share_empty")) - case .archiveError: fallthrough - case .fileError: - return .error(title: L("dialog_routing_system_error"), text: L("bookmarks_error_message_share_general")) - } + func shareCategory(category: BMCCategory, handler: @escaping onPreparedToShareHandler) { + onPreparedToShareCategory = handler + BM.shareCategory(category.identifier) } - func endShareCategory(category: BMCCategory) { - BM.endShareCategory(category.identifier) + func finishShareCategory() { + BM.finishShareCategory() + onPreparedToShareCategory = nil } func pendingPermission(isPending: Bool) { @@ -209,4 +205,16 @@ extension BMCDefaultViewModel: MWMBookmarksObserver { func onBookmarkDeleted(_: MWMMarkID) { loadData() } + + func onBookmarksCategoryFilePrepared(_ status: MWMBookmarksShareStatus) { + switch status { + case .success: + onPreparedToShareCategory?(.success(BM.shareCategoryURL())) + case .emptyCategory: + onPreparedToShareCategory?(.error(title: L("bookmarks_error_title_share_empty"), text: L("bookmarks_error_message_share_empty"))) + case .archiveError: fallthrough + case .fileError: + onPreparedToShareCategory?(.error(title: L("dialog_routing_system_error"), text: L("bookmarks_error_message_share_general"))) + } + } } diff --git a/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCViewModel.swift b/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCViewModel.swift index 9321db2aa9..455f76452b 100644 --- a/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCViewModel.swift +++ b/iphone/Maps/Bookmarks/Categories/BMCViewModel/BMCViewModel.swift @@ -32,8 +32,9 @@ protocol BMCViewModel: AnyObject { func deleteCategory(category: BMCCategory) func checkCategory(name: String) -> Bool - func beginShareCategory(category: BMCCategory) -> BMCShareCategoryStatus - func endShareCategory(category: BMCCategory) + typealias onPreparedToShareHandler = (BMCShareCategoryStatus) -> Void + func shareCategory(category: BMCCategory, handler: @escaping onPreparedToShareHandler) + func finishShareCategory() func pendingPermission(isPending: Bool) func grant(permission: BMCPermission?) diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h index 2ee5ca2542..f401c3e7dc 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h @@ -24,9 +24,9 @@ + (void)deleteBookmark:(MWMMarkID)bookmarkId; + (BOOL)checkCategoryName:(NSString *)name; -+ (MWMBookmarksShareStatus)beginShareCategory:(MWMMarkGroupID)groupId; ++ (void)shareCategory:(MWMMarkGroupID)groupId; + (NSURL *)shareCategoryURL; -+ (void)endShareCategory:(MWMMarkGroupID)groupId; ++ (void)finishShareCategory; + (NSDate *)lastSynchronizationDate; + (BOOL)isCloudEnabled; diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm index 17ade6d106..038d8edd87 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm @@ -4,6 +4,8 @@ #include "Framework.h" +#include "coding/internal/file_data.hpp" + namespace { using Observer = id; @@ -188,25 +190,38 @@ using TLoopBlock = void (^)(Observer observer); return !GetFramework().GetBookmarkManager().IsUsedCategoryName(name.UTF8String); } -+ (MWMBookmarksShareStatus)beginShareCategory:(MWMMarkGroupID)groupId ++ (void)shareCategory:(MWMMarkGroupID)groupId { - auto const sharingResult = GetFramework().GetBookmarkManager().BeginSharing(groupId); - switch (sharingResult.m_code) - { - case BookmarkManager::SharingResult::Code::Success: + GetFramework().GetBookmarkManager().PrepareFileForSharing(groupId, [](auto sharingResult) { + MWMBookmarksShareStatus status; MWMBookmarksManager * manager = [MWMBookmarksManager manager]; - manager.shareCategoryURL = - [NSURL fileURLWithPath:@(sharingResult.m_sharingPath.c_str()) isDirectory:NO]; - NSAssert(manager.shareCategoryURL != nil, @"Invalid share category url"); - return MWMBookmarksShareStatusSuccess; - } - case BookmarkManager::SharingResult::Code::EmptyCategory: - return MWMBookmarksShareStatusEmptyCategory; - case BookmarkManager::SharingResult::Code::ArchiveError: - return MWMBookmarksShareStatusArchiveError; - case BookmarkManager::SharingResult::Code::FileError: return MWMBookmarksShareStatusFileError; - } + switch (sharingResult.m_code) + { + case BookmarkManager::SharingResult::Code::Success: + { + manager.shareCategoryURL = [NSURL fileURLWithPath:@(sharingResult.m_sharingPath.c_str()) + isDirectory:NO]; + NSAssert(manager.shareCategoryURL != nil, @"Invalid share category url"); + status = MWMBookmarksShareStatusSuccess; + break; + } + case BookmarkManager::SharingResult::Code::EmptyCategory: + status = MWMBookmarksShareStatusEmptyCategory; + break; + case BookmarkManager::SharingResult::Code::ArchiveError: + status = MWMBookmarksShareStatusArchiveError; + break; + case BookmarkManager::SharingResult::Code::FileError: + status = MWMBookmarksShareStatusFileError; + break; + } + + [manager loopObservers:^(Observer observer) { + if ([observer respondsToSelector:@selector(onBookmarksCategoryFilePrepared:)]) + [observer onBookmarksCategoryFilePrepared:status]; + }]; + }); } + (NSURL *)shareCategoryURL @@ -216,11 +231,14 @@ using TLoopBlock = void (^)(Observer observer); return manager.shareCategoryURL; } -+ (void)endShareCategory:(MWMMarkGroupID)groupId ++ (void)finishShareCategory { MWMBookmarksManager * manager = [MWMBookmarksManager manager]; + if (!manager.shareCategoryURL) + return; + + my::DeleteFileX(manager.shareCategoryURL.path.UTF8String); manager.shareCategoryURL = nil; - GetFramework().GetBookmarkManager().EndSharing(groupId); } + (NSDate *)lastSynchronizationDate diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksObserver.h b/iphone/Maps/Core/Bookmarks/MWMBookmarksObserver.h index 8a8040de99..f6582f0623 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksObserver.h +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksObserver.h @@ -7,5 +7,6 @@ - (void)onBookmarksFileLoadSuccess; - (void)onBookmarksCategoryDeleted:(MWMMarkGroupID)groupId; - (void)onBookmarkDeleted:(MWMMarkID)bookmarkId; +- (void)onBookmarksCategoryFilePrepared:(MWMBookmarksShareStatus)status; @end diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 1fbc0beece..25040cdb27 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -110,6 +110,38 @@ public: m2::AnyRectD const & m_rect; m2::PointD m_globalCenter; }; + +BookmarkManager::SharingResult GetFileForSharing(df::MarkGroupID categoryId, std::string const & filePath) +{ + if (!GetPlatform().IsFileExistsByFullPath(filePath)) + { + return BookmarkManager::SharingResult(categoryId, BookmarkManager::SharingResult::Code::FileError, + "Bookmarks file does not exist."); + } + + auto ext = my::GetFileExtension(filePath); + strings::AsciiToLower(ext); + std::string fileName = filePath; + my::GetNameFromFullPath(fileName); + my::GetNameWithoutExt(fileName); + auto const tmpFilePath = my::JoinFoldersToPath(GetPlatform().TmpDir(), fileName + KMZ_EXTENSION); + if (ext == KMZ_EXTENSION) + { + if (my::CopyFileX(filePath, tmpFilePath)) + return BookmarkManager::SharingResult(categoryId, tmpFilePath); + + return BookmarkManager::SharingResult(categoryId, BookmarkManager::SharingResult::Code::FileError, + "Could not copy file."); + } + + if (!CreateZipFromPathDeflatedAndDefaultCompression(filePath, tmpFilePath)) + { + return BookmarkManager::SharingResult(categoryId, BookmarkManager::SharingResult::Code::ArchiveError, + "Could not create archive."); + } + + return BookmarkManager::SharingResult(categoryId, tmpFilePath); +} } // namespace namespace migration @@ -1457,37 +1489,21 @@ void BookmarkManager::SetInvalidTokenHandler(Cloud::InvalidTokenHandler && onInv m_bookmarkCloud.SetInvalidTokenHandler(std::move(onInvalidToken)); } -BookmarkManager::SharingResult BookmarkManager::BeginSharing(df::MarkGroupID categoryId) +void BookmarkManager::PrepareFileForSharing(df::MarkGroupID categoryId, SharingHandler && handler) { - auto const it = m_activeSharing.find(categoryId); - if (it != m_activeSharing.end()) + ASSERT_THREAD_CHECKER(m_threadChecker, ()); + ASSERT(handler, ()); + if (IsCategoryEmpty(categoryId)) { - // In case if the sharing has already begun. - if (GetPlatform().IsFileExistsByFullPath(it->second)) - return SharingResult(it->second); - } - - auto const result = GetFileForSharing(categoryId); - if (result.m_code != SharingResult::Code::Success) - { - m_activeSharing.erase(categoryId); - return result; - } - - m_activeSharing[categoryId] = result.m_sharingPath; - return result; -} - -void BookmarkManager::EndSharing(df::MarkGroupID categoryId) -{ - auto const it = m_activeSharing.find(categoryId); - if (it == m_activeSharing.end()) + handler(SharingResult(categoryId, SharingResult::Code::EmptyCategory)); return; + } - if (GetPlatform().IsFileExistsByFullPath(it->second)) - my::DeleteFileX(it->second); - - m_activeSharing.erase(categoryId); + auto const filePath = GetCategoryFileName(categoryId); + GetPlatform().RunTask(Platform::Thread::File, [categoryId, filePath, handler = std::move(handler)]() + { + handler(GetFileForSharing(categoryId, filePath)); + }); } bool BookmarkManager::IsCategoryEmpty(df::MarkGroupID categoryId) const @@ -1536,36 +1552,6 @@ void BookmarkManager::SetAllCategoriesVisibility(bool visible) c.second->SetIsVisible(visible); } -BookmarkManager::SharingResult BookmarkManager::GetFileForSharing(df::MarkGroupID categoryId) -{ - ASSERT_THREAD_CHECKER(m_threadChecker, ()); - if (IsCategoryEmpty(categoryId)) - return SharingResult(SharingResult::Code::EmptyCategory); - - auto const filePath = GetCategoryFileName(categoryId); - if (!GetPlatform().IsFileExistsByFullPath(filePath)) - return SharingResult(SharingResult::Code::FileError, "Bookmarks file does not exist."); - - auto ext = my::GetFileExtension(filePath); - strings::AsciiToLower(ext); - std::string fileName = filePath; - my::GetNameFromFullPath(fileName); - my::GetNameWithoutExt(fileName); - auto const tmpFilePath = my::JoinFoldersToPath(GetPlatform().TmpDir(), fileName + KMZ_EXTENSION); - if (ext == KMZ_EXTENSION) - { - if (my::CopyFileX(filePath, tmpFilePath)) - return SharingResult(tmpFilePath); - - return SharingResult(SharingResult::Code::FileError, "Could not copy file."); - } - - if (!CreateZipFromPathDeflatedAndDefaultCompression(filePath, tmpFilePath)) - return SharingResult(SharingResult::Code::ArchiveError, "Could not create archive."); - - return SharingResult(tmpFilePath); -} - size_t BookmarkManager::GetKmlFilesCountForConversion() const { // The conversion available only after successful migration. diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index ae8b1bb0f7..be6059a036 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -204,27 +204,31 @@ public: ArchiveError, FileError }; + df::MarkGroupID m_categoryId; Code m_code; std::string m_sharingPath; std::string m_errorString; - explicit SharingResult(std::string const & sharingPath) - : m_code(Code::Success) + SharingResult(df::MarkGroupID categoryId, std::string const & sharingPath) + : m_categoryId(categoryId) + , m_code(Code::Success) , m_sharingPath(sharingPath) {} - explicit SharingResult(Code code) - : m_code(code) + SharingResult(df::MarkGroupID categoryId, Code code) + : m_categoryId(categoryId) + , m_code(code) {} - SharingResult(Code code, std::string const & errorString) - : m_code(code) + SharingResult(df::MarkGroupID categoryId, Code code, std::string const & errorString) + : m_categoryId(categoryId) + , m_code(code) , m_errorString(errorString) {} }; - SharingResult BeginSharing(df::MarkGroupID categoryId); - void EndSharing(df::MarkGroupID categoryId); + using SharingHandler = platform::SafeCallback; + void PrepareFileForSharing(df::MarkGroupID categoryId, SharingHandler && handler); bool IsCategoryEmpty(df::MarkGroupID categoryId) const; @@ -251,7 +255,7 @@ private: class MarksChangesTracker : public df::UserMarksProvider { public: - MarksChangesTracker(BookmarkManager & bmManager) : m_bmManager(bmManager) {} + explicit MarksChangesTracker(BookmarkManager & bmManager) : m_bmManager(bmManager) {} void OnAddMark(df::MarkID markId); void OnDeleteMark(df::MarkID markId); @@ -393,8 +397,6 @@ private: void SaveToKML(BookmarkCategory * group, std::ostream & s); - SharingResult GetFileForSharing(df::MarkGroupID categoryId); - ThreadChecker m_threadChecker; Callbacks m_callbacks; @@ -428,7 +430,7 @@ private: { std::string m_filename; bool m_isTemporaryFile = false; - BookmarkLoaderInfo() {} + BookmarkLoaderInfo() = default; BookmarkLoaderInfo(std::string const & filename, bool isTemporaryFile) : m_filename(filename), m_isTemporaryFile(isTemporaryFile) {} @@ -437,7 +439,5 @@ private: Cloud m_bookmarkCloud; - std::map m_activeSharing; - DISALLOW_COPY_AND_MOVE(BookmarkManager); };