diff --git a/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift b/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift index 98765d093f..e0d07dddd7 100644 --- a/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift +++ b/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift @@ -75,6 +75,7 @@ final class BMCViewController: MWMViewController { private func shareCategory(category: BMCCategory, anchor: UIView) { let storyboard = UIStoryboard.instance(.sharing) let shareController = storyboard.instantiateInitialViewController() as! BookmarksSharingViewController + shareController.categoryId = category.identifier MapViewController.topViewController().navigationController?.pushViewController(shareController, animated: true) diff --git a/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingFlow.storyboard b/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingFlow.storyboard index 8aeaf0f049..149c278b72 100644 --- a/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingFlow.storyboard +++ b/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingFlow.storyboard @@ -44,17 +44,41 @@ + + + + + + + + + + + + + + + + + + @@ -65,7 +89,7 @@ - - + + - - + + - + - + @@ -107,8 +131,8 @@ - - + + @@ -118,7 +142,7 @@ - + @@ -141,28 +165,52 @@ + + + + + + + + + + + + + + + + + + - + @@ -194,6 +242,7 @@ + @@ -201,5 +250,6 @@ + diff --git a/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingViewController.swift b/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingViewController.swift index 2d5c79a499..94d084aebb 100644 --- a/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingViewController.swift +++ b/iphone/Maps/Bookmarks/Categories/Sharing/BookmarksSharingViewController.swift @@ -3,6 +3,9 @@ import SafariServices final class BookmarksSharingViewController: MWMTableViewController { typealias ViewModel = MWMAuthorizationViewModel + var categoryId: MWMMarkGroupID? + var categoryUrl: URL? + @IBOutlet weak var uploadAndPublishCell: UploadActionCell! @IBOutlet weak var getDirectLinkCell: UploadActionCell! @@ -21,12 +24,21 @@ final class BookmarksSharingViewController: MWMTableViewController { super.viewDidLoad() title = L("sharing_options") //"Sharing options" - self.configureActionCells() + configureActionCells() + + assert(categoryId != nil, "We can't share nothing") } func configureActionCells() { - uploadAndPublishCell.config(title: L("upload_and_publish"), image: UIImage(named: "ic24PxGlobe")!) - getDirectLinkCell.config(title: L("upload_and_get_direct_link"), image: UIImage(named: "ic24PxLink")!) + uploadAndPublishCell.config(titles: [ .normal : L("upload_and_publish"), + .inProgress : L("upload_and_publish_progress_text"), + .completed : L("upload_and_publish_success") ], + image: UIImage(named: "ic24PxGlobe"), + delegate: self) + getDirectLinkCell.config(titles: [ .normal : L("upload_and_get_direct_link"), + .inProgress : L("direct_link_progress_text"), + .completed : L("direct_link_success") ], + image: UIImage(named: "ic24PxLink"), delegate: self) } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { @@ -38,27 +50,56 @@ final class BookmarksSharingViewController: MWMTableViewController { return section == 0 ? L("public_access") : L("limited_access") } + override func tableView(_ tableView: UITableView, + willSelectRowAt indexPath: IndexPath) -> IndexPath? { + let cell = tableView.cellForRow(at: indexPath) + if cell == getDirectLinkCell { + if getDirectLinkCell.cellState != .normal { + return nil + } + } + + return indexPath + } + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let cell = tableView.cellForRow(at: indexPath) - if (cell == self.uploadAndPublishCell) { - self.uploadAndPublish() - } else if (cell == self.getDirectLinkCell) { - self.getDirectLink() + if cell == uploadAndPublishCell { + uploadAndPublish() + } else if cell == getDirectLinkCell { + uploadAndGetDirectLink() } } func uploadAndPublish() { - self.performAfterValidation { + performAfterValidation { //implementation } } - func getDirectLink() { - self.performAfterValidation { - //implementation + func uploadAndGetDirectLink() { + performAfterValidation { [weak self] in + guard let categoryId = self?.categoryId else { + assert(false, "categoryId must not be nil") + return + } + + MWMBookmarksManager.shared().uploadAndGetDirectLinkCategory(withId: categoryId, progress: { (progress) in + if progress == .uploadStarted { + self?.getDirectLinkCell.cellState = .inProgress + } + }, completion: { (url, error) in + if error != nil { + self?.getDirectLinkCell.cellState = .normal + //handle errors + } else { + self?.getDirectLinkCell.cellState = .completed + self?.categoryUrl = url + } + }) } } @@ -76,7 +117,15 @@ final class BookmarksSharingViewController: MWMTableViewController { extension BookmarksSharingViewController: UITextViewDelegate { func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { let safari = SFSafariViewController(url: URL) - self.present(safari, animated: true, completion: nil) + present(safari, animated: true, completion: nil) return false; } } + +extension BookmarksSharingViewController: UploadActionCellDelegate { + func cellDidPressShareButton(_ cell: UploadActionCell) { + let message = L("share_bookmarks_email_body") + let shareController = MWMActivityViewController.share(for: categoryUrl, message: message) + shareController?.present(inParentViewController: self, anchorView: nil) + } +} diff --git a/iphone/Maps/Bookmarks/Categories/Sharing/UploadActionCell.swift b/iphone/Maps/Bookmarks/Categories/Sharing/UploadActionCell.swift index 1c943d5e61..860c3f41c6 100644 --- a/iphone/Maps/Bookmarks/Categories/Sharing/UploadActionCell.swift +++ b/iphone/Maps/Bookmarks/Categories/Sharing/UploadActionCell.swift @@ -1,14 +1,65 @@ -final class UploadActionCell: MWMTableViewCell { - @IBOutlet private weak var actionImage: UIImageView! { +protocol UploadActionCellDelegate: AnyObject { + func cellDidPressShareButton(_ cell: UploadActionCell) +} + +enum UploadActionCellState: String { + case normal + case inProgress + case completed +} + +final class UploadActionCell: MWMTableViewCell { + @IBOutlet private weak var actionImage: UIImageView! + @IBOutlet private weak var actionTitle: UILabel! + @IBOutlet private weak var progressView: UIView! + @IBOutlet private weak var shareButton: UIButton! + + weak var delegate: UploadActionCellDelegate? + private var titles: [UploadActionCellState : String]? + private lazy var progress: MWMCircularProgress = { + return MWMCircularProgress(parentView: self.progressView) + }() + + func config(titles: [UploadActionCellState : String], image: UIImage?, delegate: UploadActionCellDelegate?) { + actionImage.image = image + self.titles = titles + self.delegate = delegate + self.cellState = .normal + } + + var cellState: UploadActionCellState = .normal { didSet { - actionImage.tintColor = .linkBlue() + switch cellState { + case .normal: + progress.state = .normal + actionImage.tintColor = .linkBlue() + actionTitle.textColor = .linkBlue() + actionTitle.font = .regular16() + actionTitle.text = titles?[.normal] + shareButton.isHidden = true + break + case .inProgress: + progress.state = .spinner + actionImage.tintColor = .blackSecondaryText() + actionTitle.textColor = .blackSecondaryText() + actionTitle.font = .italic16() + actionTitle.text = titles?[.inProgress] + shareButton.isHidden = true + break + case .completed: + progress.state = .completed + actionImage.tintColor = .blackSecondaryText() + actionTitle.textColor = .blackSecondaryText() + actionTitle.font = .regular16() + actionTitle.text = titles?[.completed] + shareButton.isHidden = false + break + } } } - @IBOutlet private weak var actionTitle: UILabel! - - func config(title: String, image: UIImage) { - actionImage.image = image - actionTitle.text = title + @IBAction func shareButtonPressed(_ sender: Any) { + assert(cellState == .completed, "Share button can only be pressed while the cell is in .completed state") + delegate?.cellDidPressShareButton(self) } } diff --git a/iphone/Maps/Categories/UIFont+MapsMeFonts.h b/iphone/Maps/Categories/UIFont+MapsMeFonts.h index 3466c8c89f..60c5979783 100644 --- a/iphone/Maps/Categories/UIFont+MapsMeFonts.h +++ b/iphone/Maps/Categories/UIFont+MapsMeFonts.h @@ -39,6 +39,7 @@ + (UIFont *)bold28; + (UIFont *)bold36; + (UIFont *)bold48; ++ (UIFont *)italic16; + (UIFont *)fontWithName:(NSString *)fontName; diff --git a/iphone/Maps/Categories/UIFont+MapsMeFonts.mm b/iphone/Maps/Categories/UIFont+MapsMeFonts.mm index 185d7e860c..fe8925f2db 100644 --- a/iphone/Maps/Categories/UIFont+MapsMeFonts.mm +++ b/iphone/Maps/Categories/UIFont+MapsMeFonts.mm @@ -44,6 +44,7 @@ NSString * const kLightFontName = @"HelveticaNeue-Light"; + (UIFont *)bold28 { return [UIFont boldSystemFontOfSize:28]; } + (UIFont *)bold36 { return [UIFont boldSystemFontOfSize:26]; } + (UIFont *)bold48 { return [UIFont boldSystemFontOfSize:48]; } ++ (UIFont *)italic16 { return [UIFont italicSystemFontOfSize:16]; } + (UIFont *)fontWithName:(NSString *)fontName { #pragma clang diagnostic push diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h index 74366e6403..95f4650b61 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h @@ -53,12 +53,16 @@ NS_ASSUME_NONNULL_BEGIN - (void)downloadItemWithId:(NSString *)itemId name:(NSString *)name progress:(_Nullable ProgressBlock)progress - completion:(_Nullable CompletionBlock)completion; + completion:(_Nullable DownloadCompletionBlock)completion; - (BOOL)isCategoryFromCatalog:(MWMMarkGroupID)groupId; - (NSArray *)categoriesFromCatalog; - (NSInteger)getCatalogDownloadsCount; - (BOOL)isCategoryDownloading:(NSString *)itemId; - (BOOL)hasCategoryDownloaded:(NSString *)itemId; +- (void)uploadAndGetDirectLinkCategoryWithId:(MWMMarkGroupID)itemId + progress:(ProgressBlock)progress + completion:(UploadCompletionBlock)completion; + @end NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm index 92d3491da5..19faf666c3 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm @@ -158,14 +158,22 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result) [self.catalogObservers removeObjectForKey:observer.categoryId]; } }; - auto onUploadStarted = [](kml::MarkGroupId originCategoryId) + auto onUploadStarted = [self](kml::MarkGroupId originCategoryId) { - //TODO(@beloal): Implement me. + auto observer = self.catalogObservers[[NSString stringWithFormat:@"%lld", originCategoryId]]; + if (observer) + [observer onUploadStart]; }; - auto onUploadFinished = [](BookmarkCatalog::UploadResult uploadResult,std::string const & description, + auto onUploadFinished = [self](BookmarkCatalog::UploadResult uploadResult,std::string const & description, kml::MarkGroupId originCategoryId, kml::MarkGroupId resultCategoryId) { - //TODO(@beloal): Implement me. + auto observer = self.catalogObservers[[NSString stringWithFormat:@"%lld", originCategoryId]]; + if (observer) + { + NSURL * url = [self sharingUrlForCategoryId:resultCategoryId]; + [observer onUploadComplete:uploadResult withUrl:url]; + [self.catalogObservers removeObjectForKey:observer.categoryId]; + } }; self.bm.SetCatalogHandlers(std::move(onDownloadStarted), std::move(onDownloadFinished), @@ -499,16 +507,28 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result) - (void)downloadItemWithId:(NSString *)itemId name:(NSString *)name progress:(ProgressBlock)progress - completion:(CompletionBlock)completion + completion:(DownloadCompletionBlock)completion { auto observer = [[MWMCatalogObserver alloc] init]; observer.categoryId = itemId; observer.progressBlock = progress; - observer.completionBlock = completion; + observer.downloadCompletionBlock = completion; [self.catalogObservers setObject:observer forKey:itemId]; self.bm.DownloadFromCatalogAndImport(itemId.UTF8String, name.UTF8String); } +- (void)uploadAndGetDirectLinkCategoryWithId:(MWMMarkGroupID)itemId + progress:(ProgressBlock)progress + completion:(UploadCompletionBlock)completion +{ + auto observer = [[MWMCatalogObserver alloc] init]; + observer.categoryId = [NSString stringWithFormat:@"%lld", itemId]; + observer.progressBlock = progress; + observer.uploadCompletionBlock = completion; + [self.catalogObservers setObject:observer forKey:observer.categoryId]; + GetFramework().GetBookmarkManager().UploadToCatalog(itemId, kml::AccessRules::DirectLink); +} + - (BOOL)isCategoryFromCatalog:(MWMMarkGroupID)groupId { return self.bm.IsCategoryFromCatalog(groupId); diff --git a/iphone/Maps/Core/Bookmarks/MWMCatalogCommon.h b/iphone/Maps/Core/Bookmarks/MWMCatalogCommon.h index 70f2939141..e6bc96cfec 100644 --- a/iphone/Maps/Core/Bookmarks/MWMCatalogCommon.h +++ b/iphone/Maps/Core/Bookmarks/MWMCatalogCommon.h @@ -3,7 +3,8 @@ typedef NS_ENUM(NSInteger, MWMCategoryProgress) MWMCategoryProgressDownloadStarted, MWMCategoryProgressDownloadFinished, MWMCategoryProgressImportStarted, - MWMCategoryProgressImportFinished + MWMCategoryProgressImportFinished, + MWMCategoryProgressUploadStarted }; typedef NS_ENUM(NSInteger, MWMCategoryDownloadStatus) @@ -14,13 +15,26 @@ typedef NS_ENUM(NSInteger, MWMCategoryDownloadStatus) MWMCategoryDownloadStatusDiskError }; +typedef NS_ENUM(NSInteger, MWMCategoryUploadStatus) +{ + MWMCategoryUploadStatusNetworkError, + MWMCategoryUploadStatusServerError, + MWMCategoryUploadStatusAuthError, + MWMCategoryUploadStatusMalformedData, + MWMCategoryUploadStatusAccessError, + MWMCategoryUploadStatusInvalidCall +}; + static NSErrorDomain const kCatalogErrorDomain = @"com.mapswithme.catalog.error"; static NSInteger const kCategoryDownloadFailedCode = -10; static NSInteger const kCategoryImportFailedCode = -11; +static NSInteger const kCategoryUploadFailedCode = -12; static NSString * const kCategoryDownloadStatusKey = @"kCategoryDownloadStatusKey"; +static NSString * const kCategoryUploadStatusKey = @"kCategoryUploadStatusKey"; typedef void (^ProgressBlock)(MWMCategoryProgress progress); -typedef void (^CompletionBlock)(UInt64 categoryId, NSError * error); +typedef void (^DownloadCompletionBlock)(UInt64 categoryId, NSError * error); +typedef void (^UploadCompletionBlock)(NSURL * url, NSError * error); diff --git a/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.h b/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.h index bdf2b73669..e9943df3d0 100644 --- a/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.h +++ b/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.h @@ -8,11 +8,14 @@ @property (copy, nonatomic) NSString * categoryId; @property (copy, nonatomic) ProgressBlock progressBlock; -@property (copy, nonatomic) CompletionBlock completionBlock; +@property (copy, nonatomic) DownloadCompletionBlock downloadCompletionBlock; +@property (copy, nonatomic) UploadCompletionBlock uploadCompletionBlock; - (void)onDownloadStart; - (void)onDownloadComplete:(BookmarkCatalog::DownloadResult)result; - (void)onImportStart; - (void)onImportCompleteSuccessful:(BOOL)success forCategoryId:(UInt64)categoryId; +- (void)onUploadStart; +- (void)onUploadComplete:(BookmarkCatalog::UploadResult)result withUrl:(NSURL *)categoryUrl; @end diff --git a/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.mm b/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.mm index 1ae1f3363e..41dce97e49 100644 --- a/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.mm +++ b/iphone/Maps/Core/Bookmarks/MWMCatalogObserver.mm @@ -33,10 +33,10 @@ //TODO(@beloal) break; } - if (self.completionBlock) - self.completionBlock(0, [[NSError alloc] initWithDomain:kCatalogErrorDomain - code:kCategoryDownloadFailedCode - userInfo:@{kCategoryDownloadStatusKey : @(downloadStatus)}]); + if (self.downloadCompletionBlock) + self.downloadCompletionBlock(0, [[NSError alloc] initWithDomain:kCatalogErrorDomain + code:kCategoryDownloadFailedCode + userInfo:@{kCategoryDownloadStatusKey : @(downloadStatus)}]); } - (void)onImportStart @@ -47,12 +47,52 @@ - (void)onImportCompleteSuccessful:(BOOL)success forCategoryId:(UInt64)categoryId { - if (self.completionBlock) { + if (self.downloadCompletionBlock) { NSError * error = success ? nil : [[NSError alloc] initWithDomain:kCatalogErrorDomain code:kCategoryImportFailedCode userInfo:nil]; - self.completionBlock(categoryId, error); + self.downloadCompletionBlock(categoryId, error); } } +- (void)onUploadStart +{ + if (self.progressBlock) + self.progressBlock(MWMCategoryProgressUploadStarted); +} + +- (void)onUploadComplete:(BookmarkCatalog::UploadResult)result withUrl:(NSURL *)categoryUrl +{ + MWMCategoryUploadStatus uploadStatus; + switch (result) + { + case BookmarkCatalog::UploadResult::Success: + if (self.uploadCompletionBlock) + self.uploadCompletionBlock(categoryUrl, nil); + return; + case BookmarkCatalog::UploadResult::NetworkError: + uploadStatus = MWMCategoryUploadStatusNetworkError; + break; + case BookmarkCatalog::UploadResult::ServerError: + uploadStatus = MWMCategoryUploadStatusServerError; + break; + case BookmarkCatalog::UploadResult::AuthError: + uploadStatus = MWMCategoryUploadStatusAuthError; + break; + case BookmarkCatalog::UploadResult::MalformedDataError: + uploadStatus = MWMCategoryUploadStatusMalformedData; + break; + case BookmarkCatalog::UploadResult::AccessError: + uploadStatus = MWMCategoryUploadStatusAccessError; + break; + case BookmarkCatalog::UploadResult::InvalidCall: + uploadStatus = MWMCategoryUploadStatusInvalidCall; + break; + } + if (self.uploadCompletionBlock) + self.uploadCompletionBlock(nil, [[NSError alloc] initWithDomain:kCatalogErrorDomain + code:kCategoryUploadFailedCode + userInfo:@{kCategoryUploadStatusKey : @(uploadStatus)}]); +} + @end diff --git a/iphone/Maps/Images.xcassets/Sharing/ic24PxShare.imageset/Contents.json b/iphone/Maps/Images.xcassets/Sharing/ic24PxShare.imageset/Contents.json new file mode 100644 index 0000000000..ceb50af3e1 --- /dev/null +++ b/iphone/Maps/Images.xcassets/Sharing/ic24PxShare.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic24PxShare.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/iphone/Maps/Images.xcassets/Sharing/ic24PxShare.imageset/ic24PxShare.pdf b/iphone/Maps/Images.xcassets/Sharing/ic24PxShare.imageset/ic24PxShare.pdf new file mode 100644 index 0000000000..b0692e7fae Binary files /dev/null and b/iphone/Maps/Images.xcassets/Sharing/ic24PxShare.imageset/ic24PxShare.pdf differ diff --git a/platform/http_uploader_apple.mm b/platform/http_uploader_apple.mm index c37a11e32e..72032dd3ce 100644 --- a/platform/http_uploader_apple.mm +++ b/platform/http_uploader_apple.mm @@ -91,6 +91,10 @@ NSString * boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]]; NSString * contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [uploadRequest setValue:contentType forHTTPHeaderField:@"Content-Type"]; + + [self.headers enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSString * value, BOOL * stop) { + [uploadRequest setValue:value forHTTPHeaderField:key]; + }]; NSData * postData = [self requestDataWithBoundary:boundary];