Move Folder and Container from Data to Account.

This commit is contained in:
Brent Simmons 2017-09-16 15:25:38 -07:00
parent e7794530e5
commit 5715d2f221
20 changed files with 527 additions and 343 deletions

View File

@ -1,23 +0,0 @@
//
// Account+OPMLRepresentable.swift
// DataModel
//
// Created by Brent Simmons on 7/2/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
extension Account: OPMLRepresentable {
public func OPMLString(indentLevel: Int) -> String {
var s = ""
for oneObject in topLevelObjects {
if let oneOPMLObject = oneObject as? OPMLRepresentable {
s += oneOPMLObject.OPMLString(indentLevel: indentLevel + 1)
}
}
return s
}
}

View File

@ -8,9 +8,7 @@
import Foundation
import RSCore
// Various model objects include an accountInfo property that Accounts can use to store extra data.
public typealias AccountInfo = [String: Any]
import Data
public enum AccountType: Int {
@ -53,57 +51,6 @@ public final class Account: Hashable {
}
}
extension Account: Container {
public func hasAtLeastOneFeed() -> Bool {
return !feedIDDictionary.isEmpty
}
public func flattenedFeeds() -> Set<Feed> {
return Set(feedIDDictionary.values)
}
public func existingFeed(with feedID: String) -> Feed? {
return feedIDDictionary[feedID]
}
public func canAddItem(_ item: AnyObject) -> Bool {
return delegate.canAddItem(item, toContainer: self)
}
public func isChild(_ obj: AnyObject) -> Bool {
return topLevelObjects.contains(where: { (oneObject) -> Bool in
return oneObject === obj
})
}
public func visitObjects(_ recurse: Bool, _ visitBlock: VisitBlock) -> Bool {
for oneObject in topLevelObjects {
if let oneContainer = oneObject as? Container {
if visitBlock(oneObject) {
return true
}
if recurse && oneContainer.visitObjects(recurse, visitBlock) {
return true
}
}
else {
if visitBlock(oneObject) {
return true
}
}
}
return false
}
}
extension Account: PlistProvider {
@ -112,3 +59,16 @@ extension Account: PlistProvider {
}
}
extension Account: OPMLRepresentable {
public func OPMLString(indentLevel: Int) -> String {
var s = ""
for oneObject in topLevelObjects {
if let oneOPMLObject = oneObject as? OPMLRepresentable {
s += oneOPMLObject.OPMLString(indentLevel: indentLevel + 1)
}
}
return s
}
}

View File

@ -7,11 +7,82 @@
objects = {
/* Begin PBXBuildFile section */
841973FD1F6DD1B7006346C4 /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973E51F6DD195006346C4 /* Data.framework */; };
841973FE1F6DD1BC006346C4 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973EF1F6DD19E006346C4 /* RSCore.framework */; };
841973FF1F6DD1C5006346C4 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973FA1F6DD1AC006346C4 /* RSParser.framework */; };
841974011F6DD1EC006346C4 /* Folder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974001F6DD1EC006346C4 /* Folder.swift */; };
841974181F6DD535006346C4 /* Folder+Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974171F6DD535006346C4 /* Folder+Container.swift */; };
8419741A1F6DD583006346C4 /* Account+Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974191F6DD583006346C4 /* Account+Container.swift */; };
8469F8171F6DD0AD0084783E /* Database.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8401A17D1F6DC388002B1BE2 /* Database.framework */; };
8469F81C1F6DD15E0084783E /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848935101F62486800CEBD24 /* Account.swift */; };
848935001F62484F00CEBD24 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848934F61F62484F00CEBD24 /* Account.framework */; };
848935051F62485000CEBD24 /* AccountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848935041F62485000CEBD24 /* AccountTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
8401A17C1F6DC388002B1BE2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8401A1721F6DC387002B1BE2 /* Database.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 844BEE371F0AB3AA004AB7CD;
remoteInfo = Database;
};
8401A17E1F6DC388002B1BE2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8401A1721F6DC387002B1BE2 /* Database.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 844BEE401F0AB3AB004AB7CD;
remoteInfo = DatabaseTests;
};
841973E41F6DD195006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973DF1F6DD194006346C4 /* Data.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 844BEE5B1F0AB3C8004AB7CD;
remoteInfo = Data;
};
841973E61F6DD195006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973DF1F6DD194006346C4 /* Data.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 844BEE641F0AB3C9004AB7CD;
remoteInfo = DataTests;
};
841973EE1F6DD19E006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973E81F6DD19E006346C4 /* RSCore.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 84CFF4F41AC3C69700CEA6C8;
remoteInfo = RSCore;
};
841973F01F6DD19E006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973E81F6DD19E006346C4 /* RSCore.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 84CFF4FF1AC3C69700CEA6C8;
remoteInfo = RSCoreTests;
};
841973F21F6DD19E006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973E81F6DD19E006346C4 /* RSCore.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 842DD7BC1E14993900E061EB;
remoteInfo = RSCoreiOS;
};
841973F91F6DD1AC006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 84FF5F841EFA285800C15A01;
remoteInfo = RSParser;
};
841973FB1F6DD1AC006346C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 84FF5F8D1EFA285800C15A01;
remoteInfo = RSParserTests;
};
848935011F62484F00CEBD24 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 848934ED1F62484F00CEBD24 /* Project object */;
@ -22,13 +93,20 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
8401A1721F6DC387002B1BE2 /* Database.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Database.xcodeproj; path = ../Database/Database.xcodeproj; sourceTree = "<group>"; };
841973DF1F6DD194006346C4 /* Data.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Data.xcodeproj; path = ../Data/Data.xcodeproj; sourceTree = "<group>"; };
841973E81F6DD19E006346C4 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = "<group>"; };
841974001F6DD1EC006346C4 /* Folder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folder.swift; sourceTree = "<group>"; };
8419740D1F6DD25F006346C4 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
841974171F6DD535006346C4 /* Folder+Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Container.swift"; sourceTree = "<group>"; };
841974191F6DD583006346C4 /* Account+Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Container.swift"; sourceTree = "<group>"; };
848934F61F62484F00CEBD24 /* Account.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Account.framework; sourceTree = BUILT_PRODUCTS_DIR; };
848934FA1F62484F00CEBD24 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
848934FF1F62484F00CEBD24 /* AccountTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AccountTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
848935041F62485000CEBD24 /* AccountTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTests.swift; sourceTree = "<group>"; };
848935061F62485000CEBD24 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
848935101F62486800CEBD24 /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; };
848935201F62498B00CEBD24 /* Account+OPMLRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+OPMLRepresentable.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -36,6 +114,10 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
841973FF1F6DD1C5006346C4 /* RSParser.framework in Frameworks */,
841973FE1F6DD1BC006346C4 /* RSCore.framework in Frameworks */,
841973FD1F6DD1B7006346C4 /* Data.framework in Frameworks */,
8469F8171F6DD0AD0084783E /* Database.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -50,11 +132,71 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
8401A1731F6DC387002B1BE2 /* Products */ = {
isa = PBXGroup;
children = (
8401A17D1F6DC388002B1BE2 /* Database.framework */,
8401A17F1F6DC388002B1BE2 /* DatabaseTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
841973E01F6DD194006346C4 /* Products */ = {
isa = PBXGroup;
children = (
841973E51F6DD195006346C4 /* Data.framework */,
841973E71F6DD195006346C4 /* DataTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
841973E91F6DD19E006346C4 /* Products */ = {
isa = PBXGroup;
children = (
841973EF1F6DD19E006346C4 /* RSCore.framework */,
841973F11F6DD19E006346C4 /* RSCoreTests.xctest */,
841973F31F6DD19E006346C4 /* RSCore.framework */,
);
name = Products;
sourceTree = "<group>";
};
841973F51F6DD1AC006346C4 /* Products */ = {
isa = PBXGroup;
children = (
841973FA1F6DD1AC006346C4 /* RSParser.framework */,
841973FC1F6DD1AC006346C4 /* RSParserTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
841974141F6DD4FF006346C4 /* Container */ = {
isa = PBXGroup;
children = (
8419740D1F6DD25F006346C4 /* Container.swift */,
841974191F6DD583006346C4 /* Account+Container.swift */,
841974171F6DD535006346C4 /* Folder+Container.swift */,
);
path = Container;
sourceTree = "<group>";
};
8469F80F1F6DC3C10084783E /* Frameworks */ = {
isa = PBXGroup;
children = (
8401A1721F6DC387002B1BE2 /* Database.xcodeproj */,
841973DF1F6DD194006346C4 /* Data.xcodeproj */,
841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */,
841973E81F6DD19E006346C4 /* RSCore.xcodeproj */,
);
name = Frameworks;
sourceTree = "<group>";
};
848934EC1F62484F00CEBD24 = {
isa = PBXGroup;
children = (
848935101F62486800CEBD24 /* Account.swift */,
848935201F62498B00CEBD24 /* Account+OPMLRepresentable.swift */,
841974001F6DD1EC006346C4 /* Folder.swift */,
841974141F6DD4FF006346C4 /* Container */,
8469F80F1F6DC3C10084783E /* Frameworks */,
848934FA1F62484F00CEBD24 /* Info.plist */,
848935031F62484F00CEBD24 /* AccountTests */,
848934F71F62484F00CEBD24 /* Products */,
@ -159,6 +301,24 @@
mainGroup = 848934EC1F62484F00CEBD24;
productRefGroup = 848934F71F62484F00CEBD24 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 841973E01F6DD194006346C4 /* Products */;
ProjectRef = 841973DF1F6DD194006346C4 /* Data.xcodeproj */;
},
{
ProductGroup = 8401A1731F6DC387002B1BE2 /* Products */;
ProjectRef = 8401A1721F6DC387002B1BE2 /* Database.xcodeproj */;
},
{
ProductGroup = 841973E91F6DD19E006346C4 /* Products */;
ProjectRef = 841973E81F6DD19E006346C4 /* RSCore.xcodeproj */;
},
{
ProductGroup = 841973F51F6DD1AC006346C4 /* Products */;
ProjectRef = 841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */;
},
);
projectRoot = "";
targets = (
848934F51F62484F00CEBD24 /* Account */,
@ -167,6 +327,72 @@
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
8401A17D1F6DC388002B1BE2 /* Database.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Database.framework;
remoteRef = 8401A17C1F6DC388002B1BE2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
8401A17F1F6DC388002B1BE2 /* DatabaseTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = DatabaseTests.xctest;
remoteRef = 8401A17E1F6DC388002B1BE2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973E51F6DD195006346C4 /* Data.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Data.framework;
remoteRef = 841973E41F6DD195006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973E71F6DD195006346C4 /* DataTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = DataTests.xctest;
remoteRef = 841973E61F6DD195006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973EF1F6DD19E006346C4 /* RSCore.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = RSCore.framework;
remoteRef = 841973EE1F6DD19E006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973F11F6DD19E006346C4 /* RSCoreTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = RSCoreTests.xctest;
remoteRef = 841973F01F6DD19E006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973F31F6DD19E006346C4 /* RSCore.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = RSCore.framework;
remoteRef = 841973F21F6DD19E006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973FA1F6DD1AC006346C4 /* RSParser.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = RSParser.framework;
remoteRef = 841973F91F6DD1AC006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
841973FC1F6DD1AC006346C4 /* RSParserTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = RSParserTests.xctest;
remoteRef = 841973FB1F6DD1AC006346C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
848934F41F62484F00CEBD24 /* Resources */ = {
isa = PBXResourcesBuildPhase;
@ -189,6 +415,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8469F81C1F6DD15E0084783E /* Account.swift in Sources */,
8419741A1F6DD583006346C4 /* Account+Container.swift in Sources */,
841974011F6DD1EC006346C4 /* Folder.swift in Sources */,
841974181F6DD535006346C4 /* Folder+Container.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -336,7 +566,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Account/Info.plist;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Account;
@ -360,7 +590,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Account/Info.plist;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Account;
@ -373,6 +603,7 @@
8489350E1F62485000CEBD24 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = M8L2WTLA8W;
@ -387,6 +618,7 @@
8489350F1F62485000CEBD24 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = M8L2WTLA8W;

View File

@ -0,0 +1,61 @@
//
// Account+Container.swift
// Account
//
// Created by Brent Simmons on 9/16/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
extension Account: Container {
public func hasAtLeastOneFeed() -> Bool {
return !feedIDDictionary.isEmpty
}
public func flattenedFeeds() -> Set<Feed> {
return Set(feedIDDictionary.values)
}
public func existingFeed(with feedID: String) -> Feed? {
return feedIDDictionary[feedID]
}
public func canAddItem(_ item: AnyObject) -> Bool {
return delegate.canAddItem(item, toContainer: self)
}
public func isChild(_ obj: AnyObject) -> Bool {
return topLevelObjects.contains(where: { (oneObject) -> Bool in
return oneObject === obj
})
}
public func visitObjects(_ recurse: Bool, _ visitBlock: VisitBlock) -> Bool {
for oneObject in topLevelObjects {
if let oneContainer = oneObject as? Container {
if visitBlock(oneObject) {
return true
}
if recurse && oneContainer.visitObjects(recurse, visitBlock) {
return true
}
}
else {
if visitBlock(oneObject) {
return true
}
}
}
return false
}
}

View File

@ -0,0 +1,55 @@
//
// Folder+Container.swift
// Account
//
// Created by Brent Simmons on 9/16/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
extension Folder: Container {
public func flattenedFeeds() -> Set<Feed> {
var feeds = Set<Feed>()
for oneChild in childObjects {
if let oneFeed = oneChild as? Feed {
feeds.insert(oneFeed)
}
else if let oneContainer = oneChild as? Container {
feeds.formUnion(oneContainer.flattenedFeeds())
}
}
return feeds
}
public func isChild(_ obj: AnyObject) -> Bool {
return childObjects.contains(where: { (oneObject) -> Bool in
return oneObject === obj
})
}
public func visitObjects(_ recurse: Bool, _ visitBlock: VisitBlock) -> Bool {
for oneObject in childObjects {
if let oneContainer = oneObject as? Container {
if visitBlock(oneObject) {
return true
}
if recurse && oneContainer.visitObjects(recurse, visitBlock) {
return true
}
}
else {
if visitBlock(oneObject) {
return true
}
}
}
return false
}
}

View File

@ -0,0 +1,99 @@
//
// Folder.swift
// DataModel
//
// Created by Brent Simmons on 7/1/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import Data
public final class Folder: DisplayNameProvider, UnreadCountProvider {
public let accountID: String
var childObjects = [AnyObject]()
// MARK: - DisplayNameProvider
public var nameForDisplay: String
// MARK: - UnreadCountProvider
public var unreadCount = 0 {
didSet {
if unreadCount != oldValue {
postUnreadCountDidChangeNotification()
}
}
}
// MARK: - Init
init(accountID: String, nameForDisplay: String) {
self.accountID = accountID
self.nameForDisplay = nameForDisplay
// NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
}
// MARK: Notifications
// @objc dynamic public func unreadCountDidChange(_ note: Notification) {
//
// guard let obj = note.object else {
// return
// }
// let potentialChild = obj as AnyObject
// if isChild(potentialChild) {
// updateUnreadCount()
// }
// }
// public var unreadCount = 0 {
// didSet {
// if unreadCount != oldValue {
// postUnreadCountDidChangeNotification()
// }
// }
// }
// public func updateUnreadCount() {
//
// unreadCount = calculateUnreadCount(childObjects)
// }
}
extension Folder: OPMLRepresentable {
public func OPMLString(indentLevel: Int) -> String {
let escapedTitle = nameForDisplay.rs_stringByEscapingSpecialXMLCharacters()
var s = "<outline text=\"\(escapedTitle)\" title=\"\(escapedTitle)\">\n"
s = s.rs_string(byPrependingNumberOfTabs: indentLevel)
var hasAtLeastOneChild = false
let _ = visitChildren { (oneChild) -> Bool in
if let oneOPMLObject = oneChild as? OPMLRepresentable {
s += oneOPMLObject.OPMLString(indentLevel: indentLevel + 1)
hasAtLeastOneChild = true
}
return false
}
if !hasAtLeastOneChild {
s = "<outline text=\"\(escapedTitle)\" title=\"\(escapedTitle)\"/>\n"
s = s.rs_string(byPrependingNumberOfTabs: indentLevel)
return s
}
s = s + NSString.rs_string(withNumberOfTabs: indentLevel) + "</outline>\n"
return s
}
}

View File

@ -8,10 +8,12 @@
/* 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 */; };
844BEE7B1F0AB4BE004AB7CD /* Folder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE7A1F0AB4BE004AB7CD /* Folder.swift */; };
844BEE7D1F0AB4C4004AB7CD /* Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE7C1F0AB4C4004AB7CD /* Feed.swift */; };
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE7E1F0AB4CA004AB7CD /* Article.swift */; };
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE801F0AB4D0004AB7CD /* Author.swift */; };
@ -19,12 +21,6 @@
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */; };
844BEE871F0AB4E3004AB7CD /* BatchUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE861F0AB4E3004AB7CD /* BatchUpdates.swift */; };
844BEE891F0AB4E7004AB7CD /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE881F0AB4E7004AB7CD /* Notifications.swift */; };
844BEE901F0AB4EF004AB7CD /* Feed+OPMLRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE8C1F0AB4EF004AB7CD /* Feed+OPMLRepresentable.swift */; };
844BEE911F0AB4EF004AB7CD /* Folder+OPMLRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE8D1F0AB4EF004AB7CD /* Folder+OPMLRepresentable.swift */; };
844BEE921F0AB4EF004AB7CD /* OPMLRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE8E1F0AB4EF004AB7CD /* OPMLRepresentable.swift */; };
844BEE981F0AB4F8004AB7CD /* AccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE941F0AB4F8004AB7CD /* AccountDelegate.swift */; };
844BEE991F0AB4F8004AB7CD /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE951F0AB4F8004AB7CD /* Container.swift */; };
844BEE9A1F0AB4F8004AB7CD /* DisplayNameProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE961F0AB4F8004AB7CD /* DisplayNameProvider.swift */; };
848935221F6249AC00CEBD24 /* AccountInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848935211F6249AC00CEBD24 /* AccountInfo.swift */; };
/* End PBXBuildFile section */
@ -61,12 +57,14 @@
/* Begin PBXFileReference section */
840405C91F1A8E4300DF0296 /* DatabaseID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseID.swift; sourceTree = "<group>"; };
8419741B1F6DD613006346C4 /* UnreadCountProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountProvider.swift; sourceTree = "<group>"; };
8419741F1F6DD672006346C4 /* DisplayNameProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayNameProvider.swift; sourceTree = "<group>"; };
841974221F6DD804006346C4 /* OPMLRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLRepresentable.swift; sourceTree = "<group>"; };
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 = "<group>"; };
844BEE6B1F0AB3C9004AB7CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
844BEE761F0AB444004AB7CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
844BEE7A1F0AB4BE004AB7CD /* Folder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Folder.swift; sourceTree = "<group>"; };
844BEE7C1F0AB4C4004AB7CD /* Feed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = "<group>"; };
844BEE7E1F0AB4CA004AB7CD /* Article.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Article.swift; sourceTree = "<group>"; };
844BEE801F0AB4D0004AB7CD /* Author.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Author.swift; sourceTree = "<group>"; };
@ -74,12 +72,6 @@
844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleStatus.swift; sourceTree = "<group>"; };
844BEE861F0AB4E3004AB7CD /* BatchUpdates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatchUpdates.swift; sourceTree = "<group>"; };
844BEE881F0AB4E7004AB7CD /* Notifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
844BEE8C1F0AB4EF004AB7CD /* Feed+OPMLRepresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Feed+OPMLRepresentable.swift"; sourceTree = "<group>"; };
844BEE8D1F0AB4EF004AB7CD /* Folder+OPMLRepresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Folder+OPMLRepresentable.swift"; sourceTree = "<group>"; };
844BEE8E1F0AB4EF004AB7CD /* OPMLRepresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OPMLRepresentable.swift; sourceTree = "<group>"; };
844BEE941F0AB4F8004AB7CD /* AccountDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountDelegate.swift; sourceTree = "<group>"; };
844BEE951F0AB4F8004AB7CD /* Container.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
844BEE961F0AB4F8004AB7CD /* DisplayNameProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayNameProvider.swift; sourceTree = "<group>"; };
844BEE9C1F0AB512004AB7CD /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
848935211F6249AC00CEBD24 /* AccountInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInfo.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -107,7 +99,6 @@
844BEE511F0AB3C8004AB7CD = {
isa = PBXGroup;
children = (
844BEE7A1F0AB4BE004AB7CD /* Folder.swift */,
844BEE7C1F0AB4C4004AB7CD /* Feed.swift */,
844BEE7E1F0AB4CA004AB7CD /* Article.swift */,
844BEE801F0AB4D0004AB7CD /* Author.swift */,
@ -117,8 +108,9 @@
840405C91F1A8E4300DF0296 /* DatabaseID.swift */,
844BEE861F0AB4E3004AB7CD /* BatchUpdates.swift */,
844BEE881F0AB4E7004AB7CD /* Notifications.swift */,
844BEE8A1F0AB4EF004AB7CD /* OPML */,
844BEE931F0AB4F8004AB7CD /* Protocols */,
8419741B1F6DD613006346C4 /* UnreadCountProvider.swift */,
8419741F1F6DD672006346C4 /* DisplayNameProvider.swift */,
841974221F6DD804006346C4 /* OPMLRepresentable.swift */,
844BEE761F0AB444004AB7CD /* Info.plist */,
844BEE681F0AB3C9004AB7CD /* DataTests */,
844BEE5C1F0AB3C8004AB7CD /* Products */,
@ -144,26 +136,6 @@
path = DataTests;
sourceTree = "<group>";
};
844BEE8A1F0AB4EF004AB7CD /* OPML */ = {
isa = PBXGroup;
children = (
844BEE8C1F0AB4EF004AB7CD /* Feed+OPMLRepresentable.swift */,
844BEE8D1F0AB4EF004AB7CD /* Folder+OPMLRepresentable.swift */,
844BEE8E1F0AB4EF004AB7CD /* OPMLRepresentable.swift */,
);
path = OPML;
sourceTree = "<group>";
};
844BEE931F0AB4F8004AB7CD /* Protocols */ = {
isa = PBXGroup;
children = (
844BEE941F0AB4F8004AB7CD /* AccountDelegate.swift */,
844BEE951F0AB4F8004AB7CD /* Container.swift */,
844BEE961F0AB4F8004AB7CD /* DisplayNameProvider.swift */,
);
path = Protocols;
sourceTree = "<group>";
};
844BEE9D1F0AB512004AB7CD /* Products */ = {
isa = PBXGroup;
children = (
@ -324,20 +296,16 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
844BEE911F0AB4EF004AB7CD /* Folder+OPMLRepresentable.swift in Sources */,
844BEE901F0AB4EF004AB7CD /* Feed+OPMLRepresentable.swift in Sources */,
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */,
844BEE7D1F0AB4C4004AB7CD /* Feed.swift in Sources */,
841974231F6DD804006346C4 /* OPMLRepresentable.swift in Sources */,
844BEE891F0AB4E7004AB7CD /* Notifications.swift in Sources */,
848935221F6249AC00CEBD24 /* AccountInfo.swift in Sources */,
844BEE9A1F0AB4F8004AB7CD /* DisplayNameProvider.swift in Sources */,
844BEE991F0AB4F8004AB7CD /* Container.swift in Sources */,
844BEE7B1F0AB4BE004AB7CD /* Folder.swift in Sources */,
844BEE981F0AB4F8004AB7CD /* AccountDelegate.swift in Sources */,
844BEE831F0AB4D6004AB7CD /* Attachment.swift in Sources */,
8419741C1F6DD613006346C4 /* UnreadCountProvider.swift in Sources */,
841974201F6DD672006346C4 /* DisplayNameProvider.swift in Sources */,
844BEE871F0AB4E3004AB7CD /* BatchUpdates.swift in Sources */,
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */,
844BEE921F0AB4EF004AB7CD /* OPMLRepresentable.swift in Sources */,
840405CA1F1A8E4300DF0296 /* DatabaseID.swift in Sources */,
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */,
);

View File

@ -16,7 +16,7 @@ import RSCore
private var databaseIDCache = [String: String]()
private var databaseIDCacheLock = os_unfair_lock_s()
public func databaseIDWithString(_ s: String) -> String {
func databaseIDWithString(_ s: String) -> String {
os_unfair_lock_lock(&databaseIDCacheLock)
defer {

View File

@ -9,7 +9,7 @@
import Foundation
import RSCore
public final class Feed: DisplayNameProvider, Hashable {
public final class Feed: DisplayNameProvider, UnreadCountProvider, Hashable {
public let accountID: String
public let url: String
@ -17,24 +17,29 @@ public final class Feed: DisplayNameProvider, Hashable {
public var homePageURL: String?
public var name: String?
public var editedName: String?
public var articles = Set<Article>()
public var accountInfo: AccountInfo? //If account needs to store more data
public let hashValue: Int
// MARK: - DisplayNameProvider
public var nameForDisplay: String {
get {
return (editedName ?? name) ?? NSLocalizedString("Untitled", comment: "Feed name")
}
}
// public var unreadCount = 0 {
// didSet {
// if unreadCount != oldValue {
// postUnreadCountDidChangeNotification()
// }
// }
// }
// MARK: - UnreadCountProvider
public var unreadCount = 0 {
didSet {
if unreadCount != oldValue {
postUnreadCountDidChangeNotification()
}
}
}
// MARK: - Init
public init(accountID: String, url: String, feedID: String) {
self.accountID = accountID
@ -43,19 +48,29 @@ public final class Feed: DisplayNameProvider, Hashable {
self.hashValue = accountID.hashValue ^ url.hashValue ^ feedID.hashValue
}
// public func updateUnreadCount() {
//
// unreadCount = articles.reduce(0) { (result, oneArticle) -> Int in
// if let read = oneArticle.status?.read, !read {
// return result + 1
// }
// return result
// }
// }
public class func ==(lhs: Feed, rhs: Feed) -> Bool {
return lhs === rhs
}
}
// MARK: - OPMLRepresentable
extension Feed: OPMLRepresentable {
public func OPMLString(indentLevel: Int) -> String {
let escapedName = nameForDisplay.rs_stringByEscapingSpecialXMLCharacters()
var escapedHomePageURL = ""
if let homePageURL = homePageURL {
escapedHomePageURL = homePageURL.rs_stringByEscapingSpecialXMLCharacters()
}
let escapedFeedURL = url.rs_stringByEscapingSpecialXMLCharacters()
var s = "<outline text=\"\(escapedName)\" title=\"\(escapedName)\" description=\"\" type=\"rss\" version=\"RSS\" htmlUrl=\"\(escapedHomePageURL)\" xmlUrl=\"\(escapedFeedURL)\"/>\n"
s = s.rs_string(byPrependingNumberOfTabs: indentLevel)
return s
}
}

View File

@ -1,98 +0,0 @@
//
// Folder.swift
// DataModel
//
// Created by Brent Simmons on 7/1/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
public final class Folder {
public let accountID: String
public var nameForDisplay: String
var childObjects = [AnyObject]()
init(accountID: String, nameForDisplay: String) {
self.accountID = accountID
self.nameForDisplay = nameForDisplay
// NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
}
// MARK: Notifications
// @objc dynamic public func unreadCountDidChange(_ note: Notification) {
//
// guard let obj = note.object else {
// return
// }
// let potentialChild = obj as AnyObject
// if isChild(potentialChild) {
// updateUnreadCount()
// }
// }
// public var unreadCount = 0 {
// didSet {
// if unreadCount != oldValue {
// postUnreadCountDidChangeNotification()
// }
// }
// }
// public func updateUnreadCount() {
//
// unreadCount = calculateUnreadCount(childObjects)
// }
}
extension Folder: Container {
public func flattenedFeeds() -> Set<Feed> {
var feeds = Set<Feed>()
for oneChild in childObjects {
if let oneFeed = oneChild as? Feed {
feeds.insert(oneFeed)
}
else if let oneContainer = oneChild as? Container {
feeds.formUnion(oneContainer.flattenedFeeds())
}
}
return feeds
}
public func isChild(_ obj: AnyObject) -> Bool {
return childObjects.contains(where: { (oneObject) -> Bool in
return oneObject === obj
})
}
public func visitObjects(_ recurse: Bool, _ visitBlock: VisitBlock) -> Bool {
for oneObject in childObjects {
if let oneContainer = oneObject as? Container {
if visitBlock(oneObject) {
return true
}
if recurse && oneContainer.visitObjects(recurse, visitBlock) {
return true
}
}
else {
if visitBlock(oneObject) {
return true
}
}
}
return false
}
}

View File

@ -11,9 +11,9 @@ import Foundation
public extension Notification.Name {
public static let ArticleStatusesDidChange = Notification.Name(rawValue: "ArticleStatusesDidChange")
public static let UnreadCountDidChange = Notification.Name(rawValue: "UnreadCountDidChangeNotification")
public static let DataModelDidPerformBatchUpdates = Notification.Name(rawValue: "DataModelDidPerformBatchUpdatesDidPerformBatchUpdatesNotification")
public static let AccountRefreshProgressDidChange = Notification.Name(rawValue: "AccountRefreshProgressDidChangeNotification")
public static let UnreadCountDidChange = Notification.Name(rawValue: "UnreadCountDidChange")
public static let DataModelDidPerformBatchUpdates = Notification.Name(rawValue: "DataModelDidPerformBatchUpdates")
public static let AccountRefreshProgressDidChange = Notification.Name(rawValue: "AccountRefreshProgressDidChange")
}
public let articlesKey = "articles"

View File

@ -1,28 +0,0 @@
//
// Feed+OPMLRepresentable.swift
// DataModel
//
// Created by Brent Simmons on 7/2/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import RSCore
extension Feed: OPMLRepresentable {
public func OPMLString(indentLevel: Int) -> String {
let escapedName = nameForDisplay.rs_stringByEscapingSpecialXMLCharacters()
var escapedHomePageURL = ""
if let homePageURL = homePageURL {
escapedHomePageURL = homePageURL.rs_stringByEscapingSpecialXMLCharacters()
}
let escapedFeedURL = url.rs_stringByEscapingSpecialXMLCharacters()
var s = "<outline text=\"\(escapedName)\" title=\"\(escapedName)\" description=\"\" type=\"rss\" version=\"RSS\" htmlUrl=\"\(escapedHomePageURL)\" xmlUrl=\"\(escapedFeedURL)\"/>\n"
s = s.rs_string(byPrependingNumberOfTabs: indentLevel)
return s
}
}

View File

@ -1,41 +0,0 @@
//
// Folder+OPMLRepresentable.swift
// DataModel
//
// Created by Brent Simmons on 7/2/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import RSCore
extension Folder: OPMLRepresentable {
public func OPMLString(indentLevel: Int) -> String {
let escapedTitle = nameForDisplay.rs_stringByEscapingSpecialXMLCharacters()
var s = "<outline text=\"\(escapedTitle)\" title=\"\(escapedTitle)\">\n"
s = s.rs_string(byPrependingNumberOfTabs: indentLevel)
var hasAtLeastOneChild = false
let _ = visitChildren { (oneChild) -> Bool in
if let oneOPMLObject = oneChild as? OPMLRepresentable {
s += oneOPMLObject.OPMLString(indentLevel: indentLevel + 1)
hasAtLeastOneChild = true
}
return false
}
if !hasAtLeastOneChild {
s = "<outline text=\"\(escapedTitle)\" title=\"\(escapedTitle)\"/>\n"
s = s.rs_string(byPrependingNumberOfTabs: indentLevel)
return s
}
s = s + NSString.rs_string(withNumberOfTabs: indentLevel) + "</outline>\n"
return s
}
}

View File

@ -1,16 +0,0 @@
//
// AccountDelegate.swift
// DataModel
//
// Created by Brent Simmons on 7/1/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
public protocol AccountDelegate: class {
func canAddItem(_ item: AnyObject, toContainer: Container) -> Bool
}

View File

@ -10,9 +10,7 @@ import Foundation
public protocol UnreadCountProvider {
var unreadCount: Int {get}
func updateUnreadCount()
var unreadCount: Int { get }
}
public func calculateUnreadCount<T: Collection>(_ children: T) -> Int {

View File

@ -49,9 +49,9 @@ public final class Database {
articlesTable.fetchArticlesAsync(feed, withLimits: true, resultBlock)
}
public func fetchUnreadArticles(for folder: Folder) -> Set<Article> {
public func fetchUnreadArticles(for feeds: Set<Feed>) -> Set<Article> {
return articlesTable.fetchUnreadArticles(for: folder.flattenedFeeds())
return articlesTable.fetchUnreadArticles(for: feeds)
}
// MARK: - Unread Counts

View File

@ -6,12 +6,12 @@
</editor> -->
<title>ToDo</title>
<dateCreated>Tue, 12 Sep 2017 20:15:17 GMT</dateCreated>
<expansionState>11,16,17,20,24,29,31,34,37,39,40,42,46,49,51,53,55,64</expansionState>
<vertScrollState>0</vertScrollState>
<windowTop>208</windowTop>
<windowLeft>30</windowLeft>
<windowRight>762</windowRight>
<windowBottom>967</windowBottom>
<expansionState>11,16,17,20,24,29,31,34,37,39,40,42,46,49,51,53,55,64,69</expansionState>
<vertScrollState>52</vertScrollState>
<windowTop>3298</windowTop>
<windowLeft>544</windowLeft>
<windowRight>1276</windowRight>
<windowBottom>4057</windowBottom>
</head>
<body>
<outline text="App">
@ -103,6 +103,8 @@
</outline>
<outline text="Data">
<outline text="Make model classes quicklookable"/>
<outline text="Move BatchUpdates.swift somewhere"/>
<outline text="Move Notifications.swift somewhere"/>
</outline>
<outline text="RSParser">
<outline text="ParsedItem == should compare all properties"/>