From 2737f07906dba9819f1179861c1c68c63aa29243 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 12 Sep 2019 12:33:05 -0500 Subject: [PATCH] Add folder picker to share extension --- NetNewsWire.xcodeproj/project.pbxproj | 14 ++-- .../FlattenedAccountFolderPickerData.swift | 4 +- iOS/Add/AddFeedViewController.swift | 2 +- .../Base.lproj/MainInterface.storyboard | 10 +-- .../ShareFolderPickerController.swift | 50 ++++++++++++++ iOS/ShareExtension/ShareViewController.swift | 66 ++++++++++++------- 6 files changed, 111 insertions(+), 35 deletions(-) rename iOS/Add/AddFeedFolderPickerData.swift => Shared/Tree/FlattenedAccountFolderPickerData.swift (92%) create mode 100644 iOS/ShareExtension/ShareFolderPickerController.swift diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 39c7bc3df..0e225a244 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -66,6 +66,8 @@ 515D4FC123257A3200EE1167 /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */; }; 515D4FCA23257CB500EE1167 /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; }; 515D4FCC2325815A00EE1167 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; }; + 51707439232AA97100A461A3 /* ShareFolderPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */; }; + 5170743A232AABFC00A461A3 /* FlattenedAccountFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */; }; 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; }; 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; }; 5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */; }; @@ -126,7 +128,7 @@ 51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452742265091600C03939 /* MasterUnreadIndicatorView.swift */; }; 51C4527C2265091600C03939 /* MasterTimelineDefaultCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452752265091600C03939 /* MasterTimelineDefaultCellLayout.swift */; }; 51C4527F2265092C00C03939 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4527E2265092C00C03939 /* DetailViewController.swift */; }; - 51C452852265093600C03939 /* AddFeedFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */; }; + 51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */; }; 51C452862265093600C03939 /* Add.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C452822265093600C03939 /* Add.storyboard */; }; 51C452882265093600C03939 /* AddFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452842265093600C03939 /* AddFeedViewController.swift */; }; 51C4528D2265095F00C03939 /* AddFolderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4528B2265095F00C03939 /* AddFolderViewController.swift */; }; @@ -779,6 +781,7 @@ 515D4FCB2325815A00EE1167 /* SafariExt.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SafariExt.js; sourceTree = ""; }; 515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = ""; }; 515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSshareextension_target.xcconfig; sourceTree = ""; }; + 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareFolderPickerController.swift; sourceTree = ""; }; 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = ""; }; 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = ""; }; 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProgressView.swift; sourceTree = ""; }; @@ -812,7 +815,7 @@ 51C452742265091600C03939 /* MasterUnreadIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterUnreadIndicatorView.swift; sourceTree = ""; }; 51C452752265091600C03939 /* MasterTimelineDefaultCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterTimelineDefaultCellLayout.swift; sourceTree = ""; }; 51C4527E2265092C00C03939 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; - 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFeedFolderPickerData.swift; sourceTree = ""; }; + 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlattenedAccountFolderPickerData.swift; sourceTree = ""; }; 51C452822265093600C03939 /* Add.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Add.storyboard; sourceTree = ""; }; 51C452842265093600C03939 /* AddFeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFeedViewController.swift; sourceTree = ""; }; 51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = ""; }; @@ -1135,6 +1138,7 @@ 512E08DD22687FA000BDCFDD /* Tree */ = { isa = PBXGroup; children = ( + 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */, 849A97611ED9EB96007D329B /* FeedTreeControllerDelegate.swift */, 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */, ); @@ -1145,6 +1149,7 @@ isa = PBXGroup; children = ( 513C5CE8232571C2003D4054 /* ShareViewController.swift */, + 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */, 513C5CEA232571C2003D4054 /* MainInterface.storyboard */, 513C5CED232571C2003D4054 /* Info.plist */, 515D4FCB2325815A00EE1167 /* SafariExt.js */, @@ -1331,7 +1336,6 @@ 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */, 514B7D1E23219F3C00BAC947 /* AddControllerType.swift */, 51C452842265093600C03939 /* AddFeedViewController.swift */, - 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */, 51C4528B2265095F00C03939 /* AddFolderViewController.swift */, ); path = Add; @@ -2596,6 +2600,8 @@ 515D4FC123257A3200EE1167 /* FolderTreeControllerDelegate.swift in Sources */, 515D4FCA23257CB500EE1167 /* Node-Extensions.swift in Sources */, 513C5CE9232571C2003D4054 /* ShareViewController.swift in Sources */, + 5170743A232AABFC00A461A3 /* FlattenedAccountFolderPickerData.swift in Sources */, + 51707439232AA97100A461A3 /* ShareFolderPickerController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2639,7 +2645,7 @@ 5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */, 51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */, 51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */, - 51C452852265093600C03939 /* AddFeedFolderPickerData.swift in Sources */, + 51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */, 51C4526B226508F600C03939 /* MasterFeedViewController.swift in Sources */, 5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */, 84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */, diff --git a/iOS/Add/AddFeedFolderPickerData.swift b/Shared/Tree/FlattenedAccountFolderPickerData.swift similarity index 92% rename from iOS/Add/AddFeedFolderPickerData.swift rename to Shared/Tree/FlattenedAccountFolderPickerData.swift index 650e279a0..9d23c4aa4 100644 --- a/iOS/Add/AddFeedFolderPickerData.swift +++ b/Shared/Tree/FlattenedAccountFolderPickerData.swift @@ -1,5 +1,5 @@ // -// AddFeedFolderPickerData.swift +// FlattenedAccountFolderPickerData.swift // NetNewsWire // // Created by Maurice Parker on 4/16/19. @@ -12,7 +12,7 @@ import Account import RSCore import RSTree -struct AddFeedFolderPickerData { +struct FlattenedAccountFolderPickerData { var containerNames = [String]() var containers = [Container]() diff --git a/iOS/Add/AddFeedViewController.swift b/iOS/Add/AddFeedViewController.swift index 386c2a73b..27c3d2e6c 100644 --- a/iOS/Add/AddFeedViewController.swift +++ b/iOS/Add/AddFeedViewController.swift @@ -19,7 +19,7 @@ class AddFeedViewController: UITableViewController, AddContainerViewControllerCh @IBOutlet private weak var folderPickerView: UIPickerView! @IBOutlet private weak var folderLabel: UILabel! - private lazy var pickerData: AddFeedFolderPickerData = AddFeedFolderPickerData() + private lazy var pickerData: FlattenedAccountFolderPickerData = FlattenedAccountFolderPickerData() private var shouldDisplayPicker: Bool { return pickerData.containerNames.count > 1 } diff --git a/iOS/ShareExtension/Base.lproj/MainInterface.storyboard b/iOS/ShareExtension/Base.lproj/MainInterface.storyboard index 286a50894..cac1c7bb8 100644 --- a/iOS/ShareExtension/Base.lproj/MainInterface.storyboard +++ b/iOS/ShareExtension/Base.lproj/MainInterface.storyboard @@ -1,7 +1,8 @@ - + + - + @@ -9,9 +10,9 @@ - + - + @@ -19,6 +20,7 @@ + diff --git a/iOS/ShareExtension/ShareFolderPickerController.swift b/iOS/ShareExtension/ShareFolderPickerController.swift new file mode 100644 index 000000000..0385159c6 --- /dev/null +++ b/iOS/ShareExtension/ShareFolderPickerController.swift @@ -0,0 +1,50 @@ +// +// ShareFolderPickerController.swift +// NetNewsWire iOS Share Extension +// +// Created by Maurice Parker on 9/12/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit +import Account + +protocol ShareFolderPickerControllerDelegate: class { + func shareFolderPickerDidSelect(_ container: Container) +} + +class ShareFolderPickerController: UITableViewController { + + var pickerData: FlattenedAccountFolderPickerData? + var selectedContainer: Container? + + weak var delegate: ShareFolderPickerControllerDelegate? + + override func viewDidLoad() { + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return pickerData?.containerNames.count ?? 0 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) + cell.textLabel?.text = pickerData?.containerNames[indexPath.row] ?? "" + if pickerData?.containers[indexPath.row] === selectedContainer { + cell.accessoryType = .checkmark + } + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + guard let pickerData = pickerData else { return } + delegate?.shareFolderPickerDidSelect(pickerData.containers[indexPath.row]) + navigationController?.popViewController(animated: true) + } + +} diff --git a/iOS/ShareExtension/ShareViewController.swift b/iOS/ShareExtension/ShareViewController.swift index 1e5ef2642..09a9aacec 100644 --- a/iOS/ShareExtension/ShareViewController.swift +++ b/iOS/ShareExtension/ShareViewController.swift @@ -14,13 +14,21 @@ import Articles import RSCore import RSTree -class ShareViewController: SLComposeServiceViewController { +class ShareViewController: SLComposeServiceViewController, ShareFolderPickerControllerDelegate { + private var pickerData: FlattenedAccountFolderPickerData? + private var url: URL? + private var container: Container? override func viewDidLoad() { AccountManager.shared = AccountManager(accountsFolder: RSDataSubfolder(nil, "Accounts")!) + pickerData = FlattenedAccountFolderPickerData() + + if pickerData?.containers.count ?? 0 > 0 { + container = pickerData?.containers[0] + } title = "NetNewsWire" placeholder = "Feed Name (Optional)" @@ -87,18 +95,26 @@ class ShareViewController: SLComposeServiceViewController { } override func isContentValid() -> Bool { - return url != nil + return url != nil && container != nil } override func didSelectPost() { - // Temporarily hardcoded - let account = AccountManager.shared.activeAccounts.first - let container = account! + var account: Account? + if let containerAccount = container as? Account { + account = containerAccount + } else if let containerFolder = container as? Folder, let containerAccount = containerFolder.account { + account = containerAccount + } + + if let urlString = url?.absoluteString, account!.hasFeed(withURL: urlString) { + presentError(AccountError.createErrorAlreadySubscribed) + return + } let feedName = contentText.isEmpty ? nil : contentText - account!.createFeed(url: url!.absoluteString, name: feedName, container: container) { result in + account!.createFeed(url: url!.absoluteString, name: feedName, container: container!) { result in switch result { case .success: @@ -118,6 +134,10 @@ class ShareViewController: SLComposeServiceViewController { // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context. } + func shareFolderPickerDidSelect(_ container: Container) { + self.container = container + } + override func configurationItems() -> [Any]! { // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. @@ -127,28 +147,26 @@ class ShareViewController: SLComposeServiceViewController { guard let folderItem = SLComposeSheetConfigurationItem() else { return nil } folderItem.title = "Folder" - folderItem.value = "On My iPhone" - folderItem.tapHandler = { - print("Tapped that!") + + if let nameProvider = container as? DisplayNameProvider { + folderItem.value = nameProvider.nameForDisplay } - // Example how you might navigate to a UIViewController with an edit field... - // aliasConfigItem.tapHandler = { - // - // let aliasEditViewController = UIViewController() - // aliasEditViewController.navigationController?.title = "Alias" - // - // let textField = UITextField(frame: CGRectMake(10,10,self.view.frame.width - 50,50)) - // textField.borderStyle = UITextBorderStyle.RoundedRect; - // textField.placeholder = "enter your alias"; - // textField.keyboardType = UIKeyboardType.Default; - // textField.returnKeyType = UIReturnKeyType.Done; - // aliasEditViewController.view.addSubview(textField) - // - // self.pushConfigurationViewController(aliasEditViewController) - // } + folderItem.tapHandler = { + + let folderPickerController = ShareFolderPickerController() + + folderPickerController.navigationController?.title = NSLocalizedString("Folder", comment: "Folder") + folderPickerController.delegate = self + folderPickerController.pickerData = self.pickerData + folderPickerController.selectedContainer = self.container + + self.pushConfigurationViewController(folderPickerController) + + } return [folderItem, urlItem] + } }