2017-11-04 20:19:34 +01:00
|
|
|
|
//
|
|
|
|
|
// FeedListTreeControllerDelegate.swift
|
|
|
|
|
// Evergreen
|
|
|
|
|
//
|
|
|
|
|
// Created by Brent Simmons on 11/4/17.
|
|
|
|
|
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
import RSTree
|
2017-11-04 22:53:21 +01:00
|
|
|
|
import RSCore
|
2017-11-04 20:19:34 +01:00
|
|
|
|
|
|
|
|
|
// 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.)
|
|
|
|
|
// 2. Default feeds for new users — see DefaultFeeds.plist.
|
|
|
|
|
// 3. FeedList.plist — the main directory. Its top level is all folders. There are no sub-folders.
|
|
|
|
|
// It’s okay if there’s overlap: a feed may appear in multiple places.
|
|
|
|
|
// If there’s any problem with the data (wrong types), this will crash. By design.
|
|
|
|
|
|
|
|
|
|
final class FeedListTreeControllerDelegate: TreeControllerDelegate {
|
|
|
|
|
|
2017-11-04 22:53:21 +01:00
|
|
|
|
private let topLevelFeeds: Set<FeedListFeed>
|
|
|
|
|
private let folders: Set<FeedListFolder>
|
2017-11-04 20:19:34 +01:00
|
|
|
|
|
|
|
|
|
init() {
|
|
|
|
|
|
|
|
|
|
let evergreenNewsFeed = FeedListFeed(name: "Evergreen News", url: "https://ranchero.com/evergreen/feed.json", homePageURL: "https://ranchero.com/evergreen/blog/")
|
|
|
|
|
self.topLevelFeeds = Set([evergreenNewsFeed])
|
|
|
|
|
|
2017-11-04 22:53:21 +01:00
|
|
|
|
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])
|
2017-11-04 20:19:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func treeController(treeController: TreeController, childNodesFor node: Node) -> [Node]? {
|
|
|
|
|
|
2017-11-04 22:53:21 +01:00
|
|
|
|
if node.isRoot {
|
|
|
|
|
return childNodesForRootNode(node)
|
|
|
|
|
}
|
|
|
|
|
return childNodesForFolderNode(node)
|
2017-11-04 20:19:34 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-04 22:53:21 +01:00
|
|
|
|
// MARK: - Private
|
2017-11-04 20:19:34 +01:00
|
|
|
|
|
2017-11-04 22:53:21 +01:00
|
|
|
|
private extension FeedListTreeControllerDelegate {
|
2017-11-04 20:19:34 +01:00
|
|
|
|
|
2017-11-04 22:53:21 +01:00
|
|
|
|
func childNodesForRootNode(_ rootNode: Node) -> [Node]? {
|
|
|
|
|
|
2017-11-05 07:05:20 +01:00
|
|
|
|
let children = (Array(topLevelFeeds) as [AnyObject]) + (Array(folders) as [AnyObject])
|
2017-11-04 22:53:21 +01:00
|
|
|
|
return childNodesForContainerNode(rootNode, children)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func childNodesForFolderNode(_ folderNode: Node) -> [Node]? {
|
|
|
|
|
|
|
|
|
|
let folder = folderNode.representedObject as! FeedListFolder
|
|
|
|
|
return childNodesForContainerNode(folderNode, Array(folder.feeds))
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-05 07:05:20 +01:00
|
|
|
|
func childNodesForContainerNode(_ containerNode: Node, _ children: [AnyObject]) -> [Node]? {
|
2017-11-04 22:53:21 +01:00
|
|
|
|
|
|
|
|
|
let nodes = unsortedNodes(parent: containerNode, children: children)
|
2017-11-19 01:56:36 +01:00
|
|
|
|
return nodes.sortedAlphabeticallyWithFoldersAtEnd()
|
2017-11-04 22:53:21 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-05 07:05:20 +01:00
|
|
|
|
func unsortedNodes(parent: Node, children: [AnyObject]) -> [Node] {
|
2017-11-04 22:53:21 +01:00
|
|
|
|
|
|
|
|
|
return children.map{ createNode(child: $0, parent: parent) }
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-05 07:05:20 +01:00
|
|
|
|
func createNode(child: AnyObject, parent: Node) -> Node {
|
2017-11-04 22:53:21 +01:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-04 20:19:34 +01:00
|
|
|
|
|
|
|
|
|
// MARK: - Loading from Disk
|
|
|
|
|
|
|
|
|
|
private struct FeedListReader {
|
|
|
|
|
|
|
|
|
|
static func folders() -> Set<FeedListFolder> {
|
|
|
|
|
|
|
|
|
|
return Set(foldersDictionary().map { (arg: (key: String, value: [[String : String]])) -> FeedListFolder in
|
|
|
|
|
|
|
|
|
|
let (name, feedDictionaries) = arg
|
|
|
|
|
return FeedListFolder(name: name, feeds: feeds(with: feedDictionaries))
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static func defaultFeeds() -> Set<FeedListFeed> {
|
|
|
|
|
|
|
|
|
|
return feeds(with: defaultFeedDictionaries())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static func defaultFeedDictionaries() -> [[String: String]] {
|
|
|
|
|
|
|
|
|
|
let f = Bundle.main.path(forResource: "DefaultFeeds", ofType: "plist")!
|
|
|
|
|
return NSArray(contentsOfFile: f)! as! [[String: String]]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static func foldersDictionary() -> [String: [[String: String]]] {
|
|
|
|
|
|
|
|
|
|
let f = Bundle.main.path(forResource: "FeedList", ofType: "plist")!
|
|
|
|
|
return NSDictionary(contentsOfFile: f)! as! [String: [[String: String]]]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static func feeds(with dictionaries: [[String: String]]) -> Set<FeedListFeed> {
|
|
|
|
|
|
|
|
|
|
return Set(dictionaries.map { FeedListFeed(dictionary: $0) })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|