NetNewsWire/Frameworks/LocalAccount/LocalFolder.swift
2017-05-27 10:43:27 -07:00

241 lines
4.8 KiB
Swift

//
// LocalFolder.swift
// Evergreen
//
// Created by Brent Simmons on 4/23/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import RSCore
import DataModel
let folderIDKey = "folderID"
private let folderNameKey = "name"
// LocalFolders can contain LocalFeeds only. Sub-folders are not allowed.
public final class LocalFolder: Folder, PlistProvider {
public var nameForDisplay: String
public let account: Account?
public var feeds = [String: LocalFeed]()
let folderID: String
public var unreadCount = 0 {
didSet {
postUnreadCountDidChangeNotification()
}
}
public var plist: AnyObject? {
get {
return createDiskDictionary()
}
}
init(nameForDisplay: String, folderID: String, account: Account) {
self.nameForDisplay = nameForDisplay
self.folderID = folderID
self.account = account
}
convenience init(nameForDisplay: String, account: Account) {
self.init(nameForDisplay: nameForDisplay, folderID: uniqueIdentifier(), account: account)
}
// MARK: Folder
public var hasAtLeastOneFeed: Bool {
get {
return !feeds.isEmpty
}
}
public var flattenedFeeds: NSSet {
get {
return Set(feeds.values) as NSSet
}
}
public var flattenedFeedIDs: Set<String> {
get {
return Set(feeds.keys)
}
}
public func fetchArticles() -> [Article] {
if let account = account as? LocalAccount {
let articlesSet = account.fetchArticlesForFolder(self)
return articlesSet.map { $0 as Article }
}
return [Article]()
}
public func objectIsChild(_ obj: AnyObject) -> Bool {
if let feed = obj as? LocalFeed {
return feeds[feed.feedID] != nil
}
return false
}
public func objectIsDescendant(_ obj: AnyObject) -> Bool {
return objectIsChild(obj)
}
public func visitObjects(_ recurse: Bool, visitBlock: FolderVisitBlock) -> Bool {
for oneFeed in feeds.values {
if visitBlock(oneFeed) {
return true
}
}
return false
}
public func existingFeedWithID(_ feedID: String) -> Feed? {
return feeds[feedID] as Feed?
}
public func existingFeedWithURL(_ urlString: String) -> Feed? {
return feeds[urlString] as Feed?
}
public func existingFolderWithName(_ name: String) -> Folder? {
return nil
}
public func canAddItem(_ item: AnyObject) -> Bool {
return item is LocalFeed
}
public func addItem(_ item: AnyObject) -> Bool {
guard let feed = item as? LocalFeed else {
return false
}
if let _ = existingFeedWithID(feed.feedID) {
return true
}
feeds[feed.feedID] = feed
FolderPostChildrenDidChangeNotification(self)
return true
}
public func canAddFolderWithName(_ folderName: String) -> Bool {
return false
}
public func ensureFolderWithName(_ folderName: String) -> Folder? {
return nil
}
public func createFeedWithName(_ name: String?, editedName: String?, urlString: String) -> Feed? {
return account?.createFeedWithName(name, editedName: editedName, urlString: urlString)
}
public func deleteItems(_ items: [AnyObject]) {
deleteFeeds(feedsWithItems(items))
FolderPostChildrenDidChangeNotification(self)
updateUnreadCount()
}
// MARK: UnreadCountProvider
public func updateUnreadCount() {
let updatedUnreadCount = calculateUnreadCount(feeds.values)
if updatedUnreadCount != unreadCount {
unreadCount = updatedUnreadCount
}
}
}
// MARK: Disk
extension LocalFolder {
convenience init?(account: LocalAccount, diskDictionary: NSDictionary) {
guard let folderID = diskDictionary[folderIDKey] as? String else {
return nil
}
guard let folderName = diskDictionary[folderNameKey] as? String else {
return nil
}
self.init(nameForDisplay: folderName, folderID: folderID, account: account as Account)
if let childrenDiskArray = diskDictionary[diskDictionaryChildrenKey] as? NSArray {
let childrenArray = account.childrenForDiskArray(childrenDiskArray)
childrenArray.forEach{ (oneItem) in
if let oneFeed = oneItem as? LocalFeed {
feeds[oneFeed.feedID] = oneFeed
}
}
}
}
}
// MARK: Private
private extension LocalFolder {
func createDiskDictionary() -> NSDictionary {
let d = NSMutableDictionary()
d.setObjectWithStringKey(folderID as NSString, folderIDKey)
d.setObjectWithStringKey(nameForDisplay as NSString, folderNameKey)
if unreadCount > 0 {
d.setObjectWithStringKey(NSNumber(value: unreadCount), unreadCountKey)
}
let children = NSMutableArray()
feeds.values.forEach { (oneLocalFeed) in
if let onePlist = oneLocalFeed.plist {
children.add(onePlist)
}
}
if children.count > 0 {
d.setObjectWithStringKey(children, diskDictionaryChildrenKey)
}
return d
}
func feedsWithItems(_ items: [AnyObject]) -> [LocalFeed] {
return items.flatMap { $0 as? LocalFeed }
}
func deleteFeeds(_ feeds: [LocalFeed]) {
feeds.forEach { deleteFeed($0) }
}
func deleteFeed(_ feed: LocalFeed) {
feeds[feed.feedID] = nil
}
}