diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 4e8bee760..029e361d3 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; }; + 51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */; }; + 51EC11A1214A94AD00B296E3 /* AddFeedFromListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51EC1193214A94AC00B296E3 /* AddFeedFromListSheet.xib */; }; + 51EC11A3214A990000B296E3 /* AddFeedFromListWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EC11A2214A990000B296E3 /* AddFeedFromListWindowController.swift */; }; 6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */; }; 6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */; }; 6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */; }; @@ -480,6 +483,9 @@ /* Begin PBXFileReference section */ 519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = ""; }; + 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FolderTreeMenu.swift; path = AddFeed/FolderTreeMenu.swift; sourceTree = ""; }; + 51EC1194214A94AC00B296E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = NetNewsWire/Base.lproj/AddFeedFromListSheet.xib; sourceTree = SOURCE_ROOT; }; + 51EC11A2214A990000B296E3 /* AddFeedFromListWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFeedFromListWindowController.swift; path = AddFeed/AddFeedFromListWindowController.swift; sourceTree = ""; }; 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Subscribe to Feed.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 6581C73420CED60100F4AD34 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = ""; }; @@ -948,10 +954,13 @@ 849A97551ED9EAC3007D329B /* Add Feed */ = { isa = PBXGroup; children = ( + 51EC1193214A94AC00B296E3 /* AddFeedFromListSheet.xib */, + 51EC11A2214A990000B296E3 /* AddFeedFromListWindowController.swift */, 849A97A71ED9F9AA007D329B /* AddFeedSheet.xib */, 849A97511ED9EAC0007D329B /* AddFeedController.swift */, 849A97521ED9EAC0007D329B /* AddFeedWindowController.swift */, 849A97A01ED9F180007D329B /* InitialFeedDownloader.swift */, + 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */, 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */, ); name = "Add Feed"; @@ -1528,8 +1537,8 @@ ORGANIZATIONNAME = "Ranchero Software"; TargetAttributes = { 6581C73220CED60000F4AD34 = { - DevelopmentTeam = M8L2WTLA8W; - ProvisioningStyle = Manual; + DevelopmentTeam = SHJK2V3AJG; + ProvisioningStyle = Automatic; }; 840D617B2029031C009BC708 = { CreatedOnToolsVersion = 9.3; @@ -1550,12 +1559,12 @@ }; 849C645F1ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = M8L2WTLA8W; - ProvisioningStyle = Manual; + DevelopmentTeam = SHJK2V3AJG; + ProvisioningStyle = Automatic; }; 849C64701ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = 9C84TZ7Q6Z; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; TestTargetID = 849C645F1ED37A5D003D8FC0; }; @@ -1811,6 +1820,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 51EC11A1214A94AD00B296E3 /* AddFeedFromListSheet.xib in Resources */, 84EB381F1FBA8B9F000D2111 /* KeyboardShortcuts.html in Resources */, 849A97951ED9EF7A007D329B /* IndeterminateProgressWindow.xib in Resources */, 844B5B651FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist in Resources */, @@ -1940,6 +1950,7 @@ 8426118A1FCB67AA0086A189 /* FeedIconDownloader.swift in Sources */, 84162A152038C12C00035290 /* MarkCommandValidationStatus.swift in Sources */, 84E95D241FB1087500552D99 /* ArticlePasteboardWriter.swift in Sources */, + 51EC11A3214A990000B296E3 /* AddFeedFromListWindowController.swift in Sources */, 849A975B1ED9EB0D007D329B /* ArticleUtilities.swift in Sources */, 84DAEE301F86CAFE0058304B /* OPMLImporter.swift in Sources */, 849A975C1ED9EB0D007D329B /* DefaultFeedsImporter.swift in Sources */, @@ -2005,6 +2016,7 @@ 84B99C691FAE36B800ECDEDB /* FeedListFolder.swift in Sources */, 84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */, 844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */, + 51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */, 849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */, 84A1500320048D660046AD9A /* SendToCommand.swift in Sources */, 845A29091FC74B8E007B49E3 /* SingleFaviconDownloader.swift in Sources */, @@ -2113,6 +2125,14 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 51EC1193214A94AC00B296E3 /* AddFeedFromListSheet.xib */ = { + isa = PBXVariantGroup; + children = ( + 51EC1194214A94AC00B296E3 /* Base */, + ); + name = AddFeedFromListSheet.xib; + sourceTree = ""; + }; 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/NetNewsWire/AppDelegate.swift b/NetNewsWire/AppDelegate.swift index a94d8405c..8e38abf8a 100644 --- a/NetNewsWire/AppDelegate.swift +++ b/NetNewsWire/AppDelegate.swift @@ -49,6 +49,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, private var readerWindows = [NSWindowController]() private var feedListWindowController: NSWindowController? private var addFeedController: AddFeedController? + private var addFeedFromListController: AddFeedFromListWindowController? private var addFolderWindowController: AddFolderWindowController? private var keyboardShortcutsWindowController: WebViewWindowController? private var inspectorWindowController: InspectorWindowController? @@ -101,6 +102,18 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, addFeedController = AddFeedController(hostWindow: window) addFeedController?.showAddFeedSheet(urlString, name) } + + func showAddFeedFromListOnMainWindow(_ feedListFeeds: [FeedListFeed]) { + + addFeedFromListController = AddFeedFromListWindowController(feedListFeeds) + + createAndShowMainWindow() + + let isDisplayingSheet = mainWindowController?.isDisplayingSheet ?? false + if !isDisplayingSheet, let mainWindow = mainWindowController?.window { + addFeedFromListController!.runSheetOnWindow(mainWindow) + } + } // MARK: - NSApplicationDelegate diff --git a/NetNewsWire/Base.lproj/AddFeedFromListSheet.xib b/NetNewsWire/Base.lproj/AddFeedFromListSheet.xib new file mode 100644 index 000000000..a622517e9 --- /dev/null +++ b/NetNewsWire/Base.lproj/AddFeedFromListSheet.xib @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetNewsWire/FeedList/FeedListViewController.swift b/NetNewsWire/FeedList/FeedListViewController.swift index 6d7ca1790..1557180ca 100644 --- a/NetNewsWire/FeedList/FeedListViewController.swift +++ b/NetNewsWire/FeedList/FeedListViewController.swift @@ -76,8 +76,10 @@ extension FeedListViewController { } @IBAction func addToFeeds(_ sender: Any?) { - + let selectedFeeds = selectedObjects.map { $0 as! FeedListFeed } + appDelegate.showAddFeedFromListOnMainWindow(selectedFeeds) } + } // MARK: - NSOutlineViewDataSource diff --git a/NetNewsWire/MainWindow/AddFeed/AddFeedFromListWindowController.swift b/NetNewsWire/MainWindow/AddFeed/AddFeedFromListWindowController.swift new file mode 100644 index 000000000..d27cd8e5c --- /dev/null +++ b/NetNewsWire/MainWindow/AddFeed/AddFeedFromListWindowController.swift @@ -0,0 +1,122 @@ +// +// AddFeedFromListWindowController.swift +// NetNewsWire +// +// Created by Maurice Parker on 9/13/18. +// Copyright © 2018 Ranchero Software, LLC. All rights reserved. +// + +import AppKit +import RSCore +import RSTree +import Articles +import Account + + +class AddFeedFromListWindowController : NSWindowController { + + @IBOutlet weak var addFeedTextField: NSTextField! + @IBOutlet weak var folderPopupButton: NSPopUpButton! + + private var feedListFeeds: [FeedListFeed]? + private var hostWindow: NSWindow! + private var folderTreeController: TreeController? + + convenience init(_ feedListFeeds: [FeedListFeed]) { + self.init(windowNibName: NSNib.Name(rawValue: "AddFeedFromListSheet")) + self.feedListFeeds = feedListFeeds + } + + func runSheetOnWindow(_ w: NSWindow) { + hostWindow = w + if let sheetWindow = self.window { + hostWindow.beginSheet(sheetWindow) { (returnCode: NSApplication.ModalResponse) -> Void in + } + } + } + + override func windowDidLoad() { + + guard let feedListFeeds = feedListFeeds else { + assertionFailure("Feeds should have been passed in the initializer") + return + } + + if feedListFeeds.count == 1 { + addFeedTextField.stringValue = "Add \"\(feedListFeeds.first!.nameForDisplay)\"?" + } else { + addFeedTextField.stringValue = "Add \(feedListFeeds.count) feeds?" + } + + let rootNode = Node(representedObject: AccountManager.shared.localAccount, parent: nil) + rootNode.canHaveChildNodes = true + folderTreeController = TreeController(delegate: FolderTreeControllerDelegate(), rootNode: rootNode) + + folderPopupButton.menu = FolderTreeMenu.createFolderPopupMenu(with: folderTreeController!.rootNode) + + } + + + // MARK: Actions + + @IBAction func cancel(_ sender: Any?) { + if let sheetWindow = window { + hostWindow.endSheet(sheetWindow, returnCode: NSApplication.ModalResponse.cancel) + } + } + + @IBAction func addFeed(_ sender: Any?) { + + guard let container = folderPopupButton.selectedItem?.representedObject as? Container else { + assertionFailure("Expected the folderPopupButton to have a container.") + return + } + + guard let feedListFeeds = feedListFeeds else { + assertionFailure("Feeds should have been passed in the initializer") + return + } + + var account: Account? + var folder: Folder? + if container is Folder { + folder = (container as! Folder) + account = folder!.account + } else { + account = (container as! Account) + } + + for feedListFeed in feedListFeeds { + + if account!.hasFeed(withURL: feedListFeed.url) { + continue + } + + guard let feed = account!.createFeed(with: feedListFeed.nameForDisplay, editedName: nil, url: feedListFeed.url) else { + continue + } + + guard let url = URL(string: feedListFeed.url) else { + assertionFailure("Malformed URL string: \(feedListFeed.url).") + continue + } + + if account!.addFeed(feed, to: folder) { + NotificationCenter.default.post(name: .UserDidAddFeed, object: self, userInfo: [UserInfoKey.feed: feed]) + } + + InitialFeedDownloader.download(url) { (parsedFeed) in + if let parsedFeed = parsedFeed { + account!.update(feed, with: parsedFeed, {}) + } + } + + } + + if let sheetWindow = window { + hostWindow.endSheet(sheetWindow, returnCode: NSApplication.ModalResponse.OK) + } + + } + +} diff --git a/NetNewsWire/MainWindow/AddFeed/AddFeedWindowController.swift b/NetNewsWire/MainWindow/AddFeed/AddFeedWindowController.swift index 78e3f92b0..451f801d7 100644 --- a/NetNewsWire/MainWindow/AddFeed/AddFeedWindowController.swift +++ b/NetNewsWire/MainWindow/AddFeed/AddFeedWindowController.swift @@ -68,7 +68,7 @@ class AddFeedWindowController : NSWindowController { nameTextField.stringValue = initialName } - folderPopupButton.menu = createFolderPopupMenu() + folderPopupButton.menu = FolderTreeMenu.createFolderPopupMenu(with: folderTreeController.rootNode) updateUI() } @@ -139,35 +139,4 @@ private extension AddFeedWindowController { return folderPopupButton.selectedItem?.representedObject as? Container } - func createFolderPopupMenu() -> NSMenu { - - let menu = NSMenu(title: "Folders") - - let menuItem = NSMenuItem(title: NSLocalizedString("Top Level", comment: "Add Feed Sheet"), action: nil, keyEquivalent: "") - menuItem.representedObject = folderTreeController.rootNode.representedObject - menu.addItem(menuItem) - - let childNodes = folderTreeController.rootNode.childNodes - addFolderItemsToMenuWithNodes(menu: menu, nodes: childNodes, indentationLevel: 1) - - return menu - } - - func addFolderItemsToMenuWithNodes(menu: NSMenu, nodes: [Node], indentationLevel: Int) { - - nodes.forEach { (oneNode) in - - if let nameProvider = oneNode.representedObject as? DisplayNameProvider { - - let menuItem = NSMenuItem(title: nameProvider.nameForDisplay, action: nil, keyEquivalent: "") - menuItem.indentationLevel = indentationLevel - menuItem.representedObject = oneNode.representedObject - menu.addItem(menuItem) - - if oneNode.numberOfChildNodes > 0 { - addFolderItemsToMenuWithNodes(menu: menu, nodes: oneNode.childNodes, indentationLevel: indentationLevel + 1) - } - } - } - } } diff --git a/NetNewsWire/MainWindow/AddFeed/FolderTreeMenu.swift b/NetNewsWire/MainWindow/AddFeed/FolderTreeMenu.swift new file mode 100644 index 000000000..5b32307d3 --- /dev/null +++ b/NetNewsWire/MainWindow/AddFeed/FolderTreeMenu.swift @@ -0,0 +1,47 @@ +// +// FolderTreeMenu.swift +// NetNewsWire +// +// Created by Maurice Parker on 9/12/18. +// Copyright © 2018 Ranchero Software, LLC. All rights reserved. +// + +import AppKit +import RSCore +import RSTree + +class FolderTreeMenu { + + static func createFolderPopupMenu(with rootNode: Node) -> NSMenu { + + let menu = NSMenu(title: "Folders") + + let menuItem = NSMenuItem(title: NSLocalizedString("Top Level", comment: "Add Feed Sheet"), action: nil, keyEquivalent: "") + menuItem.representedObject = rootNode.representedObject + menu.addItem(menuItem) + + let childNodes = rootNode.childNodes + addFolderItemsToMenuWithNodes(menu: menu, nodes: childNodes, indentationLevel: 1) + + return menu + } + + private static func addFolderItemsToMenuWithNodes(menu: NSMenu, nodes: [Node], indentationLevel: Int) { + + nodes.forEach { (oneNode) in + + if let nameProvider = oneNode.representedObject as? DisplayNameProvider { + + let menuItem = NSMenuItem(title: nameProvider.nameForDisplay, action: nil, keyEquivalent: "") + menuItem.indentationLevel = indentationLevel + menuItem.representedObject = oneNode.representedObject + menu.addItem(menuItem) + + if oneNode.numberOfChildNodes > 0 { + addFolderItemsToMenuWithNodes(menu: menu, nodes: oneNode.childNodes, indentationLevel: indentationLevel + 1) + } + } + } + } + +}