From 10c405c44e51d6fd3905c7fc7030e43b89ea80af Mon Sep 17 00:00:00 2001 From: David Sinclair Date: Thu, 23 Dec 2021 16:18:26 -0700 Subject: [PATCH] #1575 (subscribe to site in share sheet) --- clients/ios/Classes/FeedsObjCViewController.m | 1 + .../Base.lproj/MainInterface.storyboard | 16 +- .../Share Extension/ShareViewController.swift | 160 +++++++++++++----- .../Share Extension/ShareViewDelegate.swift | 62 ++++++- 4 files changed, 183 insertions(+), 56 deletions(-) diff --git a/clients/ios/Classes/FeedsObjCViewController.m b/clients/ios/Classes/FeedsObjCViewController.m index 930e76872..dc5b6fefd 100644 --- a/clients/ios/Classes/FeedsObjCViewController.m +++ b/clients/ios/Classes/FeedsObjCViewController.m @@ -579,6 +579,7 @@ static NSArray *NewsBlurTopSectionNames; [defaults setObject:[results objectForKey:@"share_ext_token"] forKey:@"share:token"]; [defaults setObject:self.appDelegate.url forKey:@"share:host"]; [defaults setObject:appDelegate.dictSavedStoryTags forKey:@"share:tags"]; + [defaults setObject:appDelegate.dictFoldersArray forKey:@"share:folders"]; [self validateWidgetFeedsForGroupDefaults:defaults usingResults:results]; [defaults synchronize]; diff --git a/clients/ios/Share Extension/Base.lproj/MainInterface.storyboard b/clients/ios/Share Extension/Base.lproj/MainInterface.storyboard index 755260a6c..1ad3f38c0 100644 --- a/clients/ios/Share Extension/Base.lproj/MainInterface.storyboard +++ b/clients/ios/Share Extension/Base.lproj/MainInterface.storyboard @@ -1,8 +1,9 @@ - + - + + @@ -36,10 +37,11 @@ - + + @@ -52,7 +54,7 @@ - + @@ -76,14 +78,14 @@ - + - + @@ -105,7 +107,7 @@ - + diff --git a/clients/ios/Share Extension/ShareViewController.swift b/clients/ios/Share Extension/ShareViewController.swift index 34005cbdf..b74ca6c58 100644 --- a/clients/ios/Share Extension/ShareViewController.swift +++ b/clients/ios/Share Extension/ShareViewController.swift @@ -28,9 +28,12 @@ class ShareViewController: UIViewController { /// Share publicly. case share + + /// Add site. + case add } - /// Whether we are saving the story privately or sharing publicly. + /// Whether we are saving the story privately, sharing publicly, or adding a site. var mode: Mode = .save /// Dictionary representation of a tag. @@ -60,6 +63,15 @@ class ShareViewController: UIViewController { /// User-entered comments, only used when sharing. var comments = "" + /// An array of folders, from the main app. + var folders = [String]() + + /// New folder name, only used when adding. + var newFolder = "" + + /// Index path of the selected folder. + var selectedFolderIndexPath = IndexPath(item: 0, section: 0) + /// Title of the item being shared. var itemTitle: String? = nil @@ -83,6 +95,12 @@ class ShareViewController: UIViewController { } } + if let foldersArray = prefs.object(forKey: "share:folders") as? [String] { + folders = foldersArray + + folders.removeAll { ["river_global", "river_blurblogs", "infrequent", "read_stories", "saved_searches", "saved_stories"].contains($0) } + } + updateSaveButtonState() NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow(notification:)), name: UIResponder.keyboardDidShowNotification, object: nil) @@ -90,13 +108,14 @@ class ShareViewController: UIViewController { } func updateSaveButtonState() { - if mode == .save { + switch mode { + case .save: if let rows = tableView.indexPathsForSelectedRows { navigationItem.rightBarButtonItem?.isEnabled = !rows.isEmpty } else { navigationItem.rightBarButtonItem?.isEnabled = false } - } else { + default: navigationItem.rightBarButtonItem?.isEnabled = true } } @@ -112,12 +131,16 @@ class ShareViewController: UIViewController { } @IBAction func newTagFieldChanged(_ sender: UITextField) { - newTag = sender.text ?? "" - - if newTag.isEmpty { - tableView.deselectRow(at: indexPathForNewTag, animated: false) - } else { - tableView.selectRow(at: indexPathForNewTag, animated: false, scrollPosition: .none) + if mode == .save { + newTag = sender.text ?? "" + + if newTag.isEmpty { + tableView.deselectRow(at: indexPathForNewTag, animated: false) + } else { + tableView.selectRow(at: indexPathForNewTag, animated: false, scrollPosition: .none) + } + } else if mode == .add { + newFolder = sender.text ?? "" } updateSaveButtonState() @@ -154,9 +177,17 @@ class ShareViewController: UIViewController { } @IBAction func changedMode(_ sender: Any) { - mode = modeSegmentedControl.selectedSegmentIndex == 0 ? .save : .share - - navigationItem.rightBarButtonItem?.title = mode == .save ? "Save" : "Share" + switch modeSegmentedControl.selectedSegmentIndex { + case 1: + mode = .share + navigationItem.rightBarButtonItem?.title = "Share" + case 2: + mode = .add + navigationItem.rightBarButtonItem?.title = "Add" + default: + mode = .save + navigationItem.rightBarButtonItem?.title = "Save" + } tableView.isEditing = mode == .save tableView.reloadData() @@ -231,52 +262,89 @@ private extension ShareViewController { } var requestPath: String { - return mode == .save ? "api/save_story" : "api/share_story" + switch mode { + case .share: + return "api/share_story" + case .save: + return "api/save_story" + case .add: + return "reader/add_url" + } } func encoded(_ string: String?) -> String { return string?.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? "" } - func postBody(url: URL?, text: String?) -> String { + func postSave(url: URL?, text: String?) -> String { let title = itemTitle let encodedURL = encoded(url?.absoluteString) let encodedTitle = encoded(title) let encodedContent = encoded(text) - if mode == .save { - let indexPaths = tableView.indexPathsForSelectedRows ?? [] - var selectedTagsArray = [String]() - - for index in 0.. String { + let title = itemTitle + let encodedURL = encoded(url?.absoluteString) + let encodedTitle = encoded(title) + let encodedContent = encoded(text) + + var comments = comments + + // Don't really need this stuff if I don't populate the comments from the title or text; leave for now just in case that is wanted. + if title != nil && comments == title { + comments = "" + } + + if text != nil && comments == text { + comments = "" + } + + let encodedComments = encoded(comments) + + let postBody = "story_url=\(encodedURL)&title=\(encodedTitle)&content=\(encodedContent)&comments=\(encodedComments)" + + return postBody + } + + func postAdd(url: URL?, text: String?) -> String { + let folder = folders[selectedFolderIndexPath.row] + let encodedFolder = encoded(folder) + let encodedURL = encoded(url?.absoluteString) + + var postBody = "folder=\(encodedFolder)&url=\(encodedURL)" + + if newFolder != "" { + postBody += "&new_folder=\(encoded(newFolder))" + } + + return postBody + } + + func postBody(url: URL?, text: String?) -> String { + switch mode { + case .save: + return postSave(url: url, text: text) + case .share: + return postShare(url: url, text: text) + case .add: + return postAdd(url: url, text: text) } } } diff --git a/clients/ios/Share Extension/ShareViewDelegate.swift b/clients/ios/Share Extension/ShareViewDelegate.swift index bb87b6a4c..a57f6d14c 100644 --- a/clients/ios/Share Extension/ShareViewDelegate.swift +++ b/clients/ios/Share Extension/ShareViewDelegate.swift @@ -14,6 +14,11 @@ class ShareViewDelegate: NSObject { extension ShareViewDelegate: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if viewController.mode == .add, indexPath.section == 0 { + viewController.selectedFolderIndexPath = indexPath + tableView.reloadData() + } + viewController.updateSaveButtonState() } @@ -23,14 +28,37 @@ extension ShareViewDelegate: UITableViewDelegate { } extension ShareViewDelegate: UITableViewDataSource { - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - if viewController.mode == .save { - return viewController.tags.count + 1 + func numberOfSections(in tableView: UITableView) -> Int { + if viewController.mode == .add { + return 2 } else { return 1 } } + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + if viewController.mode == .add, section == 1 { + return "Add new sub-folder:" + } else { + return nil + } + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch viewController.mode { + case .save: + return viewController.tags.count + 1 + case .share: + return 1 + case .add: + if section == 0 { + return viewController.folders.count + } else { + return 1 + } + } + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if viewController.mode == .save { if indexPath.item < viewController.tags.count { @@ -47,6 +75,34 @@ extension ShareViewDelegate: UITableViewDataSource { } cell.tagField.text = "" + cell.tagField.placeholder = "new tag" + + return cell + } + } else if viewController.mode == .add { + if indexPath.section == 0 { + guard let cell = tableView.dequeueReusableCell(withIdentifier: ShareSaveTagCell.reuseIdentifier, for: indexPath) as? ShareSaveTagCell else { + preconditionFailure("Expected to dequeue a ShareSaveTagCell") + } + + let components = viewController.folders[indexPath.item].components(separatedBy: " ▸ ") + + if components.first == "everything" { + cell.tagLabel.text = "🗃 Top Level" + } else { + cell.tagLabel.text = "\(String(repeating: " ", count: components.count))📁 \(components.last ?? "?")" + } + + cell.accessoryType = indexPath == viewController.selectedFolderIndexPath ? .checkmark : .none + + return cell + } else { + guard let cell = tableView.dequeueReusableCell(withIdentifier: ShareSaveNewCell.reuseIdentifier, for: indexPath) as? ShareSaveNewCell else { + preconditionFailure("Expected to dequeue a ShareSaveNewCell") + } + + cell.tagField.text = viewController.newFolder + cell.tagField.placeholder = "new folder title" return cell }