Continue fixing build errors.

This commit is contained in:
Brent Simmons 2017-09-17 17:03:58 -07:00
parent 0336e30b0d
commit 92a60d8f06
7 changed files with 97 additions and 35 deletions

View File

@ -43,9 +43,19 @@ private func accountAndArticlesDictionary(_ articles: Set<Article>) -> [String:
extension Article { extension Article {
var feed: Feed? {
get {
return account?.existingFeed(with: feedID)
}
}
var status: ArticleStatus? { var status: ArticleStatus? {
get { get {
return account?.articleStatus(for: self) guard let status = account?.articleStatus(for: self) else {
assertionFailure("Expected ArticleStatus for article.status.")
return nil
}
return status
} }
} }
@ -60,4 +70,19 @@ extension Article {
return contentHTML ?? contentText ?? summary return contentHTML ?? contentText ?? summary
} }
} }
var logicalDatePublished: Date {
get {
return datePublished ?? dateModified ?? status?.dateArrived ?? Date.distantPast
}
}
var read: Bool {
get {
if let status = status {
return status.read
}
return false
}
}
} }

View File

@ -45,7 +45,7 @@ struct TimelineCellData {
self.attributedDateString = s self.attributedDateString = s
} }
else { else {
self.attributedDateString = NSAttributedString(string: self.dateString, attributes: [NSForegroundColorAttributeName: appearance.dateColor, NSFontAttributeName: appearance.dateFont]) self.attributedDateString = NSAttributedString(string: self.dateString, attributes: [NSAttributedStringKey.foregroundColor: appearance.dateColor, NSAttributedStringKey.font: appearance.dateFont])
attributedDateCache[self.dateString] = self.attributedDateString attributedDateCache[self.dateString] = self.attributedDateString
} }
@ -59,20 +59,14 @@ struct TimelineCellData {
self.attributedFeedName = s self.attributedFeedName = s
} }
else { else {
self.attributedFeedName = NSAttributedString(string: self.feedName, attributes: [NSForegroundColorAttributeName: appearance.feedNameColor, NSFontAttributeName: appearance.feedNameFont]) self.attributedFeedName = NSAttributedString(string: self.feedName, attributes: [NSAttributedStringKey.foregroundColor: appearance.feedNameColor, NSAttributedStringKey.font: appearance.feedNameFont])
attributedFeedNameCache[self.feedName] = self.attributedFeedName attributedFeedNameCache[self.feedName] = self.attributedFeedName
} }
self.showFeedName = showFeedName self.showFeedName = showFeedName
self.favicon = nil self.favicon = nil
self.read = article.read
if let status = article.status {
self.read = status.read
}
else {
self.read = false
}
} }
init() { //Empty init() { //Empty

View File

@ -124,9 +124,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView
return return
} }
let articlesSet = NSMutableSet() markArticles(Set(articles), statusKey: ArticleStatusKey.read.rawValue, flag: true)
articlesSet.addObjects(from: articles)
markArticles(articlesSet, statusKey: .read, flag: true)
reloadCellsForArticles(articles) reloadCellsForArticles(articles)
} }
@ -147,21 +145,23 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView
} }
let articles = selectedArticles let articles = selectedArticles
var markAsRead = true var markAsRead = true
if articles.first!.status.read { if let status = articles.first!.status {
markAsRead = false if status.read {
markAsRead = false
}
} }
markArticles(NSSet(array: articles), statusKey: .read, flag: markAsRead) markArticles(Set(articles), statusKey: ArticleStatusKey.read.rawValue, flag: markAsRead)
} }
@IBAction func markSelectedArticlesAsRead(_ sender: AnyObject) { @IBAction func markSelectedArticlesAsRead(_ sender: AnyObject) {
markArticles(NSSet(array: selectedArticles), statusKey: .read, flag: true) markArticles(Set(selectedArticles), statusKey: ArticleStatusKey.read.rawValue, flag: true)
} }
@IBAction func markSelectedArticlesAsUnread(_ sender: AnyObject) { @IBAction func markSelectedArticlesAsUnread(_ sender: AnyObject) {
markArticles(NSSet(array: selectedArticles), statusKey: .read, flag: false) markArticles(Set(selectedArticles), statusKey: ArticleStatusKey.read.rawValue, flag: false)
} }
// MARK: Navigation // MARK: Navigation
@ -186,11 +186,12 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView
func canMarkAllAsRead() -> Bool { func canMarkAllAsRead() -> Bool {
for oneArticle in articles { for article in articles {
if !oneArticle.status.read { if !article.read {
return true return true
} }
} }
return false return false
} }
@ -208,7 +209,7 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView
break break
} }
let article = articleAtRow(ix)! let article = articleAtRow(ix)!
if !article.status.read { if !article.read {
return ix return ix
} }
} }
@ -520,9 +521,8 @@ class TimelineViewController: NSViewController, NSTableViewDelegate, NSTableView
} }
if let selectedArticle = articleAtRow(selectedRow) { if let selectedArticle = articleAtRow(selectedRow) {
let articleSet = NSSet(array: [selectedArticle]) if (!selectedArticle.read) {
if (!selectedArticle.status.read) { markArticles(Set([selectedArticle]), statusKey: ArticleStatusKey.read.rawValue, flag: true)
markArticles(articleSet, statusKey: .read, flag: true)
} }
postTimelineSelectionDidChangeNotification(selectedArticle) postTimelineSelectionDidChangeNotification(selectedArticle)
} }

View File

@ -10,6 +10,7 @@ import Foundation
import RSCore import RSCore
import Data import Data
import RSParser import RSParser
import Database
public enum AccountType: Int { public enum AccountType: Int {
@ -31,6 +32,7 @@ public final class Account: DisplayNameProvider, Hashable {
public let hashValue: Int public let hashValue: Int
let settingsFile: String let settingsFile: String
let dataFolder: String let dataFolder: String
let database: Database
var topLevelObjects = [AnyObject]() var topLevelObjects = [AnyObject]()
var feedIDDictionary = [String: Feed]() var feedIDDictionary = [String: Feed]()
var username: String? var username: String?
@ -38,12 +40,6 @@ public final class Account: DisplayNameProvider, Hashable {
init?(dataFolder: String, settingsFile: String, type: AccountType, accountID: String) { init?(dataFolder: String, settingsFile: String, type: AccountType, accountID: String) {
self.accountID = accountID
self.type = type
self.settingsFile = settingsFile
self.dataFolder = dataFolder
self.hashValue = accountID.hashValue
switch type { switch type {
case .onMyMac: case .onMyMac:
@ -51,6 +47,15 @@ public final class Account: DisplayNameProvider, Hashable {
default: default:
return nil return nil
} }
self.accountID = accountID
self.type = type
self.settingsFile = settingsFile
self.dataFolder = dataFolder
self.hashValue = accountID.hashValue
let databaseFilePath = (dataFolder as NSString).appendingPathComponent("DB.sqlite3")
self.database = Database(databaseFilePath: databaseFilePath, accountID: accountID)
} }
// MARK: - API // MARK: - API
@ -67,12 +72,16 @@ public final class Account: DisplayNameProvider, Hashable {
public func markArticles(_ articles: Set<Article>, statusKey: String, flag: Bool) { public func markArticles(_ articles: Set<Article>, statusKey: String, flag: Bool) {
// TODO let statuses = database.statuses(for: articles)
if statuses.isEmpty {
return
}
database.mark(statuses, statusKey: statusKey, flag: flag)
} }
public func articleStatus(for article: Article) -> ArticleStatus? { public func articleStatus(for article: Article) -> ArticleStatus? {
// TODO return database.status(for: article)
} }
public func ensureFolder(with name: String) -> Folder? { public func ensureFolder(with name: String) -> Folder? {

View File

@ -131,6 +131,16 @@ final class ArticlesTable: DatabaseTable {
// MARK: Status // MARK: Status
func status(for article: Article) -> ArticleStatus? {
return statusesTable.cachedStatus(for: article.articleID)
}
func statuses(for articles: Set<Article>) -> Set<ArticleStatus> {
return statusesTable.cachedStatuses(for: articles.articleIDs())
}
func mark(_ statuses: Set<ArticleStatus>, _ statusKey: String, _ flag: Bool) { func mark(_ statuses: Set<ArticleStatus>, _ statusKey: String, _ flag: Bool) {
statusesTable.mark(statuses, statusKey, flag) statusesTable.mark(statuses, statusKey, flag)

View File

@ -24,11 +24,11 @@ public final class Database {
private let accountID: String private let accountID: String
private let articlesTable: ArticlesTable private let articlesTable: ArticlesTable
public init(databaseFile: String, accountID: String) { public init(databaseFilePath: String, accountID: String) {
self.accountID = accountID self.accountID = accountID
let queue = RSDatabaseQueue(filepath: databaseFile, excludeFromBackup: false) let queue = RSDatabaseQueue(filepath: databaseFilePath, excludeFromBackup: false)
self.articlesTable = ArticlesTable(name: DatabaseTableName.articles, accountID: accountID, queue: queue) self.articlesTable = ArticlesTable(name: DatabaseTableName.articles, accountID: accountID, queue: queue)
let createStatementsPath = Bundle(for: type(of: self)).path(forResource: "CreateStatements", ofType: "sql")! let createStatementsPath = Bundle(for: type(of: self)).path(forResource: "CreateStatements", ofType: "sql")!
@ -70,6 +70,16 @@ public final class Database {
// MARK: - Status // MARK: - Status
public func status(for article: Article) -> ArticleStatus? {
return articlesTable.status(for: article)
}
public func statuses(for articles: Set<Article>) -> Set<ArticleStatus> {
return articlesTable.statuses(for: articles)
}
public func mark(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) { public func mark(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) {
articlesTable.mark(statuses, statusKey, flag) articlesTable.mark(statuses, statusKey, flag)

View File

@ -37,6 +37,20 @@ final class StatusesTable: DatabaseTable {
return cache[articleID] return cache[articleID]
} }
func cachedStatuses(for articleIDs: Set<String>) -> Set<ArticleStatus> {
assert(Thread.isMainThread)
var statuses = Set<ArticleStatus>()
for articleID in articleIDs {
if let articleStatus = cache[articleID] {
statuses.insert(articleStatus)
}
}
return statuses
}
func addIfNotCached(_ statuses: Set<ArticleStatus>) { func addIfNotCached(_ statuses: Set<ArticleStatus>) {
if statuses.isEmpty { if statuses.isEmpty {