diff --git a/Evergreen/Base.lproj/FeedList.storyboard b/Evergreen/Base.lproj/FeedList.storyboard
index d206c0c5b..851ee605e 100644
--- a/Evergreen/Base.lproj/FeedList.storyboard
+++ b/Evergreen/Base.lproj/FeedList.storyboard
@@ -150,7 +150,7 @@
-
+
@@ -199,19 +199,19 @@
-
+
-
+
-
+
-
-
-
-
+
+
+
+
@@ -219,13 +219,17 @@
-
-
+
+
+
+
+
+
@@ -337,7 +341,4 @@
-
-
-
diff --git a/Evergreen/Extensions/Node-Extensions.swift b/Evergreen/Extensions/Node-Extensions.swift
index 03ffa5fcc..e7445fe35 100644
--- a/Evergreen/Extensions/Node-Extensions.swift
+++ b/Evergreen/Extensions/Node-Extensions.swift
@@ -9,6 +9,7 @@
import Foundation
import RSTree
import Data
+import RSCore
extension Node {
diff --git a/Evergreen/FeedList/FeedListFeed.swift b/Evergreen/FeedList/FeedListFeed.swift
index cde60f337..8a0b658ad 100644
--- a/Evergreen/FeedList/FeedListFeed.swift
+++ b/Evergreen/FeedList/FeedListFeed.swift
@@ -7,14 +7,21 @@
//
import Foundation
+import RSCore
-final class FeedListFeed: Hashable {
+final class FeedListFeed: Hashable, DisplayNameProvider {
let name: String
let url: String
let homePageURL: String
let hashValue: Int
+ var nameForDisplay: String { // DisplayNameProvider
+ get {
+ return name
+ }
+ }
+
init(name: String, url: String, homePageURL: String) {
self.name = name
diff --git a/Evergreen/FeedList/FeedListFolder.swift b/Evergreen/FeedList/FeedListFolder.swift
index 8883707a3..2f791b872 100644
--- a/Evergreen/FeedList/FeedListFolder.swift
+++ b/Evergreen/FeedList/FeedListFolder.swift
@@ -7,13 +7,21 @@
//
import Foundation
+import RSCore
+import Data
-final class FeedListFolder: Hashable {
+final class FeedListFolder: Hashable, DisplayNameProvider {
let name: String
let feeds: Set
let hashValue: Int
+ var nameForDisplay: String { // DisplayNameProvider
+ get {
+ return name
+ }
+ }
+
init(name: String, feeds: Set) {
self.name = name
diff --git a/Evergreen/FeedList/FeedListTreeControllerDelegate.swift b/Evergreen/FeedList/FeedListTreeControllerDelegate.swift
index 59bdc4a1e..f04ae16da 100644
--- a/Evergreen/FeedList/FeedListTreeControllerDelegate.swift
+++ b/Evergreen/FeedList/FeedListTreeControllerDelegate.swift
@@ -8,6 +8,7 @@
import Foundation
import RSTree
+import RSCore
// Folders and feeds that appear in the Feed Directory are pulled from three sources:
// 1. Feeds added in code here. (Evergreen News should be the only one.)
@@ -18,42 +19,77 @@ import RSTree
final class FeedListTreeControllerDelegate: TreeControllerDelegate {
- let topLevelFeeds: Set
- let defaultFeeds: Set
- let folders: Set
+ private let topLevelFeeds: Set
+ private let folders: Set
init() {
let evergreenNewsFeed = FeedListFeed(name: "Evergreen News", url: "https://ranchero.com/evergreen/feed.json", homePageURL: "https://ranchero.com/evergreen/blog/")
self.topLevelFeeds = Set([evergreenNewsFeed])
- self.defaultFeeds = FeedListReader.defaultFeeds()
- self.folders = FeedListReader.folders()
+ let defaultFeeds = FeedListReader.defaultFeeds()
+ let defaultFeedsFolder = FeedListFolder(name: NSLocalizedString("Default Feeds (for new users)", comment: "Feed Directory"), feeds: defaultFeeds)
+
+ self.folders = Set(FeedListReader.folders() + [defaultFeedsFolder])
}
func treeController(treeController: TreeController, childNodesFor node: Node) -> [Node]? {
-// if node.isRoot {
-// return childNodesForRootNode(node)
-// }
-// if node.representedObject is FeedListFolder {
-// return childNodesForFolderNode(node)
-// }
-
- return nil
+ if node.isRoot {
+ return childNodesForRootNode(node)
+ }
+ return childNodesForFolderNode(node)
}
}
+// MARK: - Private
+private extension FeedListTreeControllerDelegate {
-//private extension FeedListTreeControllerDelegate {
-//
-// func childNodesForRootNode(_ rootNode: Node) -> [Node]? {
-//
-// return childNodesForContainerNode(rootNode, AccountManager.shared.localAccount.children)
-// }
-//
-//}
+ func childNodesForRootNode(_ rootNode: Node) -> [Node]? {
+
+ let children = Array(topLevelFeeds) as [AnyObject] + Array(folders) as [AnyObject]
+ return childNodesForContainerNode(rootNode, children)
+ }
+
+ func childNodesForFolderNode(_ folderNode: Node) -> [Node]? {
+
+ let folder = folderNode.representedObject as! FeedListFolder
+ return childNodesForContainerNode(folderNode, Array(folder.feeds))
+ }
+
+ func childNodesForContainerNode(_ containerNode: Node, _ children: [AnyObject]) -> [Node]? {
+
+ let nodes = unsortedNodes(parent: containerNode, children: children)
+ return Node.nodesSortedAlphabeticallyWithFoldersAtEnd(nodes)
+ }
+
+ func unsortedNodes(parent: Node, children: [AnyObject]) -> [Node] {
+
+ return children.map{ createNode(child: $0, parent: parent) }
+ }
+
+ func createNode(child: AnyObject, parent: Node) -> Node {
+
+ if let feed = child as? FeedListFeed {
+ return createNode(feed: feed, parent: parent)
+ }
+ let folder = child as! FeedListFolder
+ return createNode(folder: folder, parent: parent)
+ }
+
+ func createNode(feed: FeedListFeed, parent: Node) -> Node {
+
+ return Node(representedObject: feed, parent: parent)
+ }
+
+ func createNode(folder: FeedListFolder, parent: Node) -> Node {
+
+ let node = Node(representedObject: folder, parent: parent)
+ node.canHaveChildNodes = true
+ return node
+ }
+}
// MARK: - Loading from Disk
diff --git a/Evergreen/FeedList/FeedListViewController.swift b/Evergreen/FeedList/FeedListViewController.swift
index cc4cf5b91..00760eaf6 100644
--- a/Evergreen/FeedList/FeedListViewController.swift
+++ b/Evergreen/FeedList/FeedListViewController.swift
@@ -8,6 +8,7 @@
import Cocoa
import RSTree
+import RSCore
final class FeedListViewController: NSViewController {
@@ -46,3 +47,55 @@ extension FeedListViewController: NSOutlineViewDataSource {
return item as! Node
}
}
+
+// MARK: - NSOutlineViewDelegate
+
+extension FeedListViewController: NSOutlineViewDelegate {
+
+ func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
+
+ let cell = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "FeedListCell"), owner: self) as! SidebarCell
+
+ let node = item as! Node
+ configure(cell, node)
+
+ return cell
+ }
+
+ func outlineViewSelectionDidChange(_ notification: Notification) {
+
+// // TODO: support multiple selection
+//
+// let selectedRow = self.outlineView.selectedRow
+//
+// if selectedRow < 0 || selectedRow == NSNotFound {
+// postSidebarSelectionDidChangeNotification(nil)
+// return
+// }
+//
+// if let selectedNode = self.outlineView.item(atRow: selectedRow) as? Node {
+// postSidebarSelectionDidChangeNotification([selectedNode.representedObject])
+// }
+ }
+
+ private func configure(_ cell: SidebarCell, _ node: Node) {
+
+ cell.objectValue = node
+ cell.name = nameFor(node)
+ cell.image = imageFor(node)
+ }
+
+ func imageFor(_ node: Node) -> NSImage? {
+
+ return nil
+ }
+
+ func nameFor(_ node: Node) -> String {
+
+ if let displayNameProvider = node.representedObject as? DisplayNameProvider {
+ return displayNameProvider.nameForDisplay
+ }
+ return ""
+ }
+
+}
diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift
index 152f5a5f5..2500c7ca1 100644
--- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift
+++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift
@@ -10,6 +10,7 @@ import Cocoa
import RSTree
import Data
import Account
+import RSCore
@objc class SidebarViewController: NSViewController, NSOutlineViewDelegate, NSOutlineViewDataSource {
diff --git a/Frameworks/Account/Folder.swift b/Frameworks/Account/Folder.swift
index ad912fbb6..1c5d0cb63 100644
--- a/Frameworks/Account/Folder.swift
+++ b/Frameworks/Account/Folder.swift
@@ -8,6 +8,7 @@
import Foundation
import Data
+import RSCore
public final class Folder: DisplayNameProvider, Container, UnreadCountProvider {
diff --git a/Frameworks/Data/Data.xcodeproj/project.pbxproj b/Frameworks/Data/Data.xcodeproj/project.pbxproj
index 64c079032..f50f29323 100644
--- a/Frameworks/Data/Data.xcodeproj/project.pbxproj
+++ b/Frameworks/Data/Data.xcodeproj/project.pbxproj
@@ -9,8 +9,6 @@
/* Begin PBXBuildFile section */
840405CA1F1A8E4300DF0296 /* DatabaseID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840405C91F1A8E4300DF0296 /* DatabaseID.swift */; };
8419741C1F6DD613006346C4 /* UnreadCountProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8419741B1F6DD613006346C4 /* UnreadCountProvider.swift */; };
- 841974201F6DD672006346C4 /* DisplayNameProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8419741F1F6DD672006346C4 /* DisplayNameProvider.swift */; };
- 841974231F6DD804006346C4 /* OPMLRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974221F6DD804006346C4 /* OPMLRepresentable.swift */; };
843079FA1F0AB57F00B4B7F7 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844BEEA31F0AB512004AB7CD /* RSCore.framework */; };
844BEE651F0AB3C9004AB7CD /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844BEE5B1F0AB3C8004AB7CD /* Data.framework */; };
844BEE6A1F0AB3C9004AB7CD /* DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE691F0AB3C9004AB7CD /* DataTests.swift */; };
@@ -56,8 +54,6 @@
/* Begin PBXFileReference section */
840405C91F1A8E4300DF0296 /* DatabaseID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseID.swift; sourceTree = ""; };
8419741B1F6DD613006346C4 /* UnreadCountProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountProvider.swift; sourceTree = ""; };
- 8419741F1F6DD672006346C4 /* DisplayNameProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayNameProvider.swift; sourceTree = ""; };
- 841974221F6DD804006346C4 /* OPMLRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLRepresentable.swift; sourceTree = ""; };
844BEE5B1F0AB3C8004AB7CD /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; };
844BEE641F0AB3C9004AB7CD /* DataTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DataTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
844BEE691F0AB3C9004AB7CD /* DataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTests.swift; sourceTree = ""; };
@@ -103,8 +99,6 @@
844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */,
840405C91F1A8E4300DF0296 /* DatabaseID.swift */,
8419741B1F6DD613006346C4 /* UnreadCountProvider.swift */,
- 8419741F1F6DD672006346C4 /* DisplayNameProvider.swift */,
- 841974221F6DD804006346C4 /* OPMLRepresentable.swift */,
844BEE761F0AB444004AB7CD /* Info.plist */,
844BEE681F0AB3C9004AB7CD /* DataTests */,
844BEE5C1F0AB3C8004AB7CD /* Products */,
@@ -293,10 +287,8 @@
files = (
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */,
844BEE7D1F0AB4C4004AB7CD /* Feed.swift in Sources */,
- 841974231F6DD804006346C4 /* OPMLRepresentable.swift in Sources */,
844BEE831F0AB4D6004AB7CD /* Attachment.swift in Sources */,
8419741C1F6DD613006346C4 /* UnreadCountProvider.swift in Sources */,
- 841974201F6DD672006346C4 /* DisplayNameProvider.swift in Sources */,
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */,
840405CA1F1A8E4300DF0296 /* DatabaseID.swift in Sources */,
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */,
diff --git a/Frameworks/RSCore/RSCore.xcodeproj/project.pbxproj b/Frameworks/RSCore/RSCore.xcodeproj/project.pbxproj
index 342e08c6e..3640b4360 100755
--- a/Frameworks/RSCore/RSCore.xcodeproj/project.pbxproj
+++ b/Frameworks/RSCore/RSCore.xcodeproj/project.pbxproj
@@ -89,6 +89,10 @@
849BF8BA1C9130150071D1DA /* DiskSaver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849BF8B91C9130150071D1DA /* DiskSaver.swift */; };
84A8358A1D4EC7B80004C598 /* PlistProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A835891D4EC7B80004C598 /* PlistProviderProtocol.swift */; };
84B890561C59CF1600D8BF23 /* NSString+ExtrasTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 84B890551C59CF1600D8BF23 /* NSString+ExtrasTests.m */; };
+ 84B99C941FAE64D500ECDEDB /* DisplayNameProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C931FAE64D400ECDEDB /* DisplayNameProvider.swift */; };
+ 84B99C951FAE64D500ECDEDB /* DisplayNameProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C931FAE64D400ECDEDB /* DisplayNameProvider.swift */; };
+ 84B99C9A1FAE650100ECDEDB /* OPMLRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C991FAE650100ECDEDB /* OPMLRepresentable.swift */; };
+ 84B99C9B1FAE650100ECDEDB /* OPMLRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C991FAE650100ECDEDB /* OPMLRepresentable.swift */; };
84BB45431D6909C700B48537 /* NSMutableDictionary-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BB45421D6909C700B48537 /* NSMutableDictionary-Extensions.swift */; };
84CFF4FA1AC3C69700CEA6C8 /* RSCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 84CFF4F91AC3C69700CEA6C8 /* RSCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
84CFF5001AC3C69700CEA6C8 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84CFF4F41AC3C69700CEA6C8 /* RSCore.framework */; };
@@ -187,6 +191,8 @@
849BF8B91C9130150071D1DA /* DiskSaver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiskSaver.swift; path = RSCore/DiskSaver.swift; sourceTree = ""; };
84A835891D4EC7B80004C598 /* PlistProviderProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlistProviderProtocol.swift; path = RSCore/PlistProviderProtocol.swift; sourceTree = ""; };
84B890551C59CF1600D8BF23 /* NSString+ExtrasTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ExtrasTests.m"; sourceTree = ""; };
+ 84B99C931FAE64D400ECDEDB /* DisplayNameProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisplayNameProvider.swift; path = RSCore/DisplayNameProvider.swift; sourceTree = ""; };
+ 84B99C991FAE650100ECDEDB /* OPMLRepresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OPMLRepresentable.swift; path = RSCore/OPMLRepresentable.swift; sourceTree = ""; };
84BB45421D6909C700B48537 /* NSMutableDictionary-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSMutableDictionary-Extensions.swift"; sourceTree = ""; };
84CFF4F41AC3C69700CEA6C8 /* RSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
84CFF4F81AC3C69700CEA6C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = RSCore/Info.plist; sourceTree = ""; };
@@ -306,6 +312,8 @@
844C915A1B65753E0051FC1B /* RSPlist.m */,
8453F7DC1BDF337800B1C8ED /* RSMacroProcessor.h */,
8453F7DD1BDF337800B1C8ED /* RSMacroProcessor.m */,
+ 84B99C931FAE64D400ECDEDB /* DisplayNameProvider.swift */,
+ 84B99C991FAE650100ECDEDB /* OPMLRepresentable.swift */,
849BF8B91C9130150071D1DA /* DiskSaver.swift */,
84A835891D4EC7B80004C598 /* PlistProviderProtocol.swift */,
842E45CB1ED623C7000A8B52 /* UniqueIdentifier.swift */,
@@ -640,6 +648,7 @@
842DD7D01E14995C00E061EB /* RSMacroProcessor.m in Sources */,
842DD7E51E14996300E061EB /* NSMutableDictionary+RSCore.m in Sources */,
842DD7F41E14996B00E061EB /* Set+Extensions.swift in Sources */,
+ 84B99C9B1FAE650100ECDEDB /* OPMLRepresentable.swift in Sources */,
842DD7D71E14996300E061EB /* NSArray+RSCore.m in Sources */,
842DD7CC1E14995C00E061EB /* RSBinaryCache.m in Sources */,
842DD7F31E14996B00E061EB /* NSMutableDictionary-Extensions.swift in Sources */,
@@ -649,6 +658,7 @@
842DD7E11E14996300E061EB /* NSFileManager+RSCore.m in Sources */,
842DD7C61E14995C00E061EB /* RSBlocks.m in Sources */,
842DD7DD1E14996300E061EB /* NSDate+RSCore.m in Sources */,
+ 84B99C951FAE64D500ECDEDB /* DisplayNameProvider.swift in Sources */,
842DD7E91E14996300E061EB /* NSNotificationCenter+RSCore.m in Sources */,
842DD7E71E14996300E061EB /* NSMutableSet+RSCore.m in Sources */,
842DD7E31E14996300E061EB /* NSMutableArray+RSCore.m in Sources */,
@@ -700,12 +710,14 @@
84CFF56A1AC3D1B000CEA6C8 /* RSScaling.m in Sources */,
84FEB4AC1D19D7F4004727E5 /* Date+Extensions.swift in Sources */,
8461387F1DB3F5BE00048B83 /* RSToolbarItem.swift in Sources */,
+ 84B99C941FAE64D500ECDEDB /* DisplayNameProvider.swift in Sources */,
84BB45431D6909C700B48537 /* NSMutableDictionary-Extensions.swift in Sources */,
845DE0F41B80477100D1571B /* NSSet+RSCore.m in Sources */,
842635591D7FA24800196285 /* NSOutlineView+Extensions.swift in Sources */,
844C915C1B65753E0051FC1B /* RSPlist.m in Sources */,
84CFF5231AC3C89D00CEA6C8 /* NSObject+RSCore.m in Sources */,
8414CBA71C95F2EA00333C12 /* Set+Extensions.swift in Sources */,
+ 84B99C9A1FAE650100ECDEDB /* OPMLRepresentable.swift in Sources */,
84E34DA61F9FA1070077082F /* UndoableCommand.swift in Sources */,
844F91D61D90D86100820C48 /* RSTransparentContainerView.m in Sources */,
84CFF56E1AC3D20A00CEA6C8 /* NSImage+RSCore.m in Sources */,
diff --git a/Frameworks/Data/DisplayNameProvider.swift b/Frameworks/RSCore/RSCore/DisplayNameProvider.swift
similarity index 100%
rename from Frameworks/Data/DisplayNameProvider.swift
rename to Frameworks/RSCore/RSCore/DisplayNameProvider.swift
diff --git a/Frameworks/Data/OPMLRepresentable.swift b/Frameworks/RSCore/RSCore/OPMLRepresentable.swift
similarity index 100%
rename from Frameworks/Data/OPMLRepresentable.swift
rename to Frameworks/RSCore/RSCore/OPMLRepresentable.swift