Merge mac-release — remove attachments.
This commit is contained in:
commit
ebd7c68396
|
@ -27,11 +27,9 @@ public struct Article: Hashable {
|
||||||
public let datePublished: Date?
|
public let datePublished: Date?
|
||||||
public let dateModified: Date?
|
public let dateModified: Date?
|
||||||
public let authors: Set<Author>?
|
public let authors: Set<Author>?
|
||||||
public let attachments: Set<Attachment>?
|
|
||||||
public let status: ArticleStatus
|
public let status: ArticleStatus
|
||||||
|
|
||||||
public init(accountID: String, articleID: String?, webFeedID: String, uniqueID: String, title: String?, contentHTML: String?, contentText: String?, url: String?, externalURL: String?, summary: String?, imageURL: String?, bannerImageURL: String?, datePublished: Date?, dateModified: Date?, authors: Set<Author>?, attachments: Set<Attachment>?, status: ArticleStatus) {
|
public init(accountID: String, articleID: String?, webFeedID: String, uniqueID: String, title: String?, contentHTML: String?, contentText: String?, url: String?, externalURL: String?, summary: String?, imageURL: String?, bannerImageURL: String?, datePublished: Date?, dateModified: Date?, authors: Set<Author>?, status: ArticleStatus) {
|
||||||
|
|
||||||
self.accountID = accountID
|
self.accountID = accountID
|
||||||
self.webFeedID = webFeedID
|
self.webFeedID = webFeedID
|
||||||
self.uniqueID = uniqueID
|
self.uniqueID = uniqueID
|
||||||
|
@ -46,7 +44,6 @@ public struct Article: Hashable {
|
||||||
self.datePublished = datePublished
|
self.datePublished = datePublished
|
||||||
self.dateModified = dateModified
|
self.dateModified = dateModified
|
||||||
self.authors = authors
|
self.authors = authors
|
||||||
self.attachments = attachments
|
|
||||||
self.status = status
|
self.status = status
|
||||||
|
|
||||||
if let articleID = articleID {
|
if let articleID = articleID {
|
||||||
|
@ -90,5 +87,4 @@ public extension Array where Element == Article {
|
||||||
func articleIDs() -> [String] {
|
func articleIDs() -> [String] {
|
||||||
return map { $0.articleID }
|
return map { $0.articleID }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
844BEE6A1F0AB3C9004AB7CD /* DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE691F0AB3C9004AB7CD /* DataTests.swift */; };
|
844BEE6A1F0AB3C9004AB7CD /* DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE691F0AB3C9004AB7CD /* DataTests.swift */; };
|
||||||
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE7E1F0AB4CA004AB7CD /* Article.swift */; };
|
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE7E1F0AB4CA004AB7CD /* Article.swift */; };
|
||||||
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE801F0AB4D0004AB7CD /* Author.swift */; };
|
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE801F0AB4D0004AB7CD /* Author.swift */; };
|
||||||
844BEE831F0AB4D6004AB7CD /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE821F0AB4D6004AB7CD /* Attachment.swift */; };
|
|
||||||
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */; };
|
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */; };
|
||||||
848E3EB420FBCFAE0004B7ED /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848E3EB320FBCFAE0004B7ED /* RSCore.framework */; };
|
848E3EB420FBCFAE0004B7ED /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848E3EB320FBCFAE0004B7ED /* RSCore.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
@ -58,7 +57,6 @@
|
||||||
844BEE761F0AB444004AB7CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; 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>"; };
|
||||||
844BEE7E1F0AB4CA004AB7CD /* Article.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Article.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>"; };
|
844BEE801F0AB4D0004AB7CD /* Author.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Author.swift; sourceTree = "<group>"; };
|
||||||
844BEE821F0AB4D6004AB7CD /* Attachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = "<group>"; };
|
|
||||||
844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleStatus.swift; sourceTree = "<group>"; };
|
844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleStatus.swift; sourceTree = "<group>"; };
|
||||||
844BEE9C1F0AB512004AB7CD /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
844BEE9C1F0AB512004AB7CD /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
||||||
848E3EB320FBCFAE0004B7ED /* RSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
848E3EB320FBCFAE0004B7ED /* RSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -95,7 +93,6 @@
|
||||||
children = (
|
children = (
|
||||||
844BEE7E1F0AB4CA004AB7CD /* Article.swift */,
|
844BEE7E1F0AB4CA004AB7CD /* Article.swift */,
|
||||||
844BEE801F0AB4D0004AB7CD /* Author.swift */,
|
844BEE801F0AB4D0004AB7CD /* Author.swift */,
|
||||||
844BEE821F0AB4D6004AB7CD /* Attachment.swift */,
|
|
||||||
844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */,
|
844BEE841F0AB4DB004AB7CD /* ArticleStatus.swift */,
|
||||||
840405C91F1A8E4300DF0296 /* DatabaseID.swift */,
|
840405C91F1A8E4300DF0296 /* DatabaseID.swift */,
|
||||||
844BEE761F0AB444004AB7CD /* Info.plist */,
|
844BEE761F0AB444004AB7CD /* Info.plist */,
|
||||||
|
@ -324,7 +321,6 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */,
|
844BEE7F1F0AB4CA004AB7CD /* Article.swift in Sources */,
|
||||||
844BEE831F0AB4D6004AB7CD /* Attachment.swift in Sources */,
|
|
||||||
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */,
|
844BEE811F0AB4D0004AB7CD /* Author.swift in Sources */,
|
||||||
840405CA1F1A8E4300DF0296 /* DatabaseID.swift in Sources */,
|
840405CA1F1A8E4300DF0296 /* DatabaseID.swift in Sources */,
|
||||||
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */,
|
844BEE851F0AB4DB004AB7CD /* ArticleStatus.swift in Sources */,
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
//
|
|
||||||
// Attachment.swift
|
|
||||||
// NetNewsWire
|
|
||||||
//
|
|
||||||
// Created by Brent Simmons on 7/1/17.
|
|
||||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public struct Attachment: Hashable {
|
|
||||||
|
|
||||||
public let attachmentID: String // Calculated
|
|
||||||
public let url: String
|
|
||||||
public let mimeType: String?
|
|
||||||
public let title: String?
|
|
||||||
public let sizeInBytes: Int?
|
|
||||||
public let durationInSeconds: Int?
|
|
||||||
|
|
||||||
public init(attachmentID: String?, url: String, mimeType: String?, title: String?, sizeInBytes: Int?, durationInSeconds: Int?) {
|
|
||||||
|
|
||||||
self.url = url
|
|
||||||
self.mimeType = mimeType
|
|
||||||
self.title = title
|
|
||||||
if let sizeInBytes = sizeInBytes, sizeInBytes > 0 {
|
|
||||||
self.sizeInBytes = sizeInBytes
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.sizeInBytes = nil
|
|
||||||
}
|
|
||||||
if let durationInSeconds = durationInSeconds, durationInSeconds > 0 {
|
|
||||||
self.durationInSeconds = durationInSeconds
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.durationInSeconds = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if let attachmentID = attachmentID {
|
|
||||||
self.attachmentID = attachmentID
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var s = url
|
|
||||||
s += mimeType ?? ""
|
|
||||||
s += title ?? ""
|
|
||||||
if let sizeInBytes = sizeInBytes {
|
|
||||||
s += "\(sizeInBytes)"
|
|
||||||
}
|
|
||||||
if let durationInSeconds = durationInSeconds {
|
|
||||||
s += "\(durationInSeconds)"
|
|
||||||
}
|
|
||||||
self.attachmentID = databaseIDWithString(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -42,7 +42,7 @@ public final class ArticlesDatabase {
|
||||||
database.executeStatements("ALTER TABLE articles add column searchRowID INTEGER;")
|
database.executeStatements("ALTER TABLE articles add column searchRowID INTEGER;")
|
||||||
}
|
}
|
||||||
database.executeStatements("CREATE INDEX if not EXISTS articles_searchRowID on articles(searchRowID);")
|
database.executeStatements("CREATE INDEX if not EXISTS articles_searchRowID on articles(searchRowID);")
|
||||||
database.executeStatements("DROP TABLE if EXISTS tags;DROP INDEX if EXISTS tags_tagName_index;DROP INDEX if EXISTS articles_feedID_index;DROP INDEX if EXISTS statuses_read_index;")
|
database.executeStatements("DROP TABLE if EXISTS tags;DROP INDEX if EXISTS tags_tagName_index;DROP INDEX if EXISTS articles_feedID_index;DROP INDEX if EXISTS statuses_read_index;DROP TABLE if EXISTS attachments;DROP TABLE if EXISTS attachmentsLookup;")
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.vacuumIfNeeded(daysBetweenVacuums: 9)
|
queue.vacuumIfNeeded(daysBetweenVacuums: 9)
|
||||||
|
@ -213,9 +213,6 @@ private extension ArticlesDatabase {
|
||||||
CREATE TABLE if not EXISTS authors (authorID TEXT NOT NULL PRIMARY KEY, name TEXT, url TEXT, avatarURL TEXT, emailAddress TEXT);
|
CREATE TABLE if not EXISTS authors (authorID TEXT NOT NULL PRIMARY KEY, name TEXT, url TEXT, avatarURL TEXT, emailAddress TEXT);
|
||||||
CREATE TABLE if not EXISTS authorsLookup (authorID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(authorID, articleID));
|
CREATE TABLE if not EXISTS authorsLookup (authorID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(authorID, articleID));
|
||||||
|
|
||||||
CREATE TABLE if not EXISTS attachments(attachmentID TEXT NOT NULL PRIMARY KEY, url TEXT NOT NULL, mimeType TEXT, title TEXT, sizeInBytes INTEGER, durationInSeconds INTEGER);
|
|
||||||
CREATE TABLE if not EXISTS attachmentsLookup(attachmentID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(attachmentID, articleID));
|
|
||||||
|
|
||||||
CREATE INDEX if not EXISTS articles_feedID_datePublished_articleID on articles (feedID, datePublished, articleID);
|
CREATE INDEX if not EXISTS articles_feedID_datePublished_articleID on articles (feedID, datePublished, articleID);
|
||||||
|
|
||||||
CREATE INDEX if not EXISTS statuses_starred_index on statuses (starred);
|
CREATE INDEX if not EXISTS statuses_starred_index on statuses (starred);
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
51C451FF2264CF2100C03939 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C451FE2264CF2100C03939 /* RSParser.framework */; };
|
51C451FF2264CF2100C03939 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C451FE2264CF2100C03939 /* RSParser.framework */; };
|
||||||
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840405CE1F1A963700DF0296 /* AttachmentsTable.swift */; };
|
|
||||||
841D4D742106B59F00DD04E6 /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D732106B59F00DD04E6 /* Articles.framework */; };
|
841D4D742106B59F00DD04E6 /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D732106B59F00DD04E6 /* Articles.framework */; };
|
||||||
84288A001F6A3C4400395871 /* DatabaseObject+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */; };
|
84288A001F6A3C4400395871 /* DatabaseObject+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */; };
|
||||||
84288A021F6A3D8000395871 /* RelatedObjectsMap+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */; };
|
84288A021F6A3D8000395871 /* RelatedObjectsMap+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */; };
|
||||||
|
@ -21,7 +20,6 @@
|
||||||
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580661F0AEBCD003CCFA1 /* Constants.swift */; };
|
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580661F0AEBCD003CCFA1 /* Constants.swift */; };
|
||||||
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580751F0AF670003CCFA1 /* Article+Database.swift */; };
|
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580751F0AF670003CCFA1 /* Article+Database.swift */; };
|
||||||
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */; };
|
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */; };
|
||||||
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */; };
|
|
||||||
8477ACBC2221E76F00DF7F37 /* SearchTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477ACBB2221E76F00DF7F37 /* SearchTable.swift */; };
|
8477ACBC2221E76F00DF7F37 /* SearchTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477ACBB2221E76F00DF7F37 /* SearchTable.swift */; };
|
||||||
848E3EB920FBCFD20004B7ED /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848E3EB820FBCFD20004B7ED /* RSCore.framework */; };
|
848E3EB920FBCFD20004B7ED /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848E3EB820FBCFD20004B7ED /* RSCore.framework */; };
|
||||||
848E3EBD20FBCFDE0004B7ED /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848E3EBC20FBCFDE0004B7ED /* RSDatabase.framework */; };
|
848E3EBD20FBCFDE0004B7ED /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 848E3EBC20FBCFDE0004B7ED /* RSDatabase.framework */; };
|
||||||
|
@ -114,7 +112,6 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
518B2EA7235130CD00400001 /* ArticlesDatabase_project_test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ArticlesDatabase_project_test.xcconfig; sourceTree = "<group>"; };
|
518B2EA7235130CD00400001 /* ArticlesDatabase_project_test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ArticlesDatabase_project_test.xcconfig; sourceTree = "<group>"; };
|
||||||
51C451FE2264CF2100C03939 /* RSParser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSParser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
51C451FE2264CF2100C03939 /* RSParser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSParser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
840405CE1F1A963700DF0296 /* AttachmentsTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentsTable.swift; sourceTree = "<group>"; };
|
|
||||||
841D4D732106B59F00DD04E6 /* Articles.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Articles.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
841D4D732106B59F00DD04E6 /* Articles.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Articles.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DatabaseObject+Database.swift"; sourceTree = "<group>"; };
|
842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DatabaseObject+Database.swift"; sourceTree = "<group>"; };
|
||||||
84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelatedObjectsMap+Database.swift"; sourceTree = "<group>"; };
|
84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelatedObjectsMap+Database.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -128,7 +125,6 @@
|
||||||
845580661F0AEBCD003CCFA1 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
845580661F0AEBCD003CCFA1 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||||
845580751F0AF670003CCFA1 /* Article+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Article+Database.swift"; path = "Extensions/Article+Database.swift"; sourceTree = "<group>"; };
|
845580751F0AF670003CCFA1 /* Article+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Article+Database.swift"; path = "Extensions/Article+Database.swift"; sourceTree = "<group>"; };
|
||||||
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "ArticleStatus+Database.swift"; path = "Extensions/ArticleStatus+Database.swift"; sourceTree = "<group>"; };
|
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "ArticleStatus+Database.swift"; path = "Extensions/ArticleStatus+Database.swift"; sourceTree = "<group>"; };
|
||||||
8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Attachment+Database.swift"; path = "Extensions/Attachment+Database.swift"; sourceTree = "<group>"; };
|
|
||||||
8461461E1F0ABC7300870CB3 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = "<group>"; };
|
8461461E1F0ABC7300870CB3 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = "<group>"; };
|
||||||
8477ACBB2221E76F00DF7F37 /* SearchTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTable.swift; sourceTree = "<group>"; };
|
8477ACBB2221E76F00DF7F37 /* SearchTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTable.swift; sourceTree = "<group>"; };
|
||||||
848E3EB820FBCFD20004B7ED /* RSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
848E3EB820FBCFD20004B7ED /* RSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -183,7 +179,6 @@
|
||||||
843577151F744FC800F460AE /* DatabaseArticle.swift */,
|
843577151F744FC800F460AE /* DatabaseArticle.swift */,
|
||||||
84E156ED1F0AB81400F8CC05 /* StatusesTable.swift */,
|
84E156ED1F0AB81400F8CC05 /* StatusesTable.swift */,
|
||||||
84F20F8E1F180D8700D8E682 /* AuthorsTable.swift */,
|
84F20F8E1F180D8700D8E682 /* AuthorsTable.swift */,
|
||||||
840405CE1F1A963700DF0296 /* AttachmentsTable.swift */,
|
|
||||||
8461462A1F0AC44100870CB3 /* Extensions */,
|
8461462A1F0AC44100870CB3 /* Extensions */,
|
||||||
84E156E81F0AB75600F8CC05 /* Info.plist */,
|
84E156E81F0AB75600F8CC05 /* Info.plist */,
|
||||||
844BEE441F0AB3AB004AB7CD /* DatabaseTests */,
|
844BEE441F0AB3AB004AB7CD /* DatabaseTests */,
|
||||||
|
@ -229,7 +224,6 @@
|
||||||
843702C21F70D15D00B18807 /* ParsedArticle+Database.swift */,
|
843702C21F70D15D00B18807 /* ParsedArticle+Database.swift */,
|
||||||
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */,
|
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */,
|
||||||
84F20F901F1810DD00D8E682 /* Author+Database.swift */,
|
84F20F901F1810DD00D8E682 /* Author+Database.swift */,
|
||||||
8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */,
|
|
||||||
842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */,
|
842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */,
|
||||||
84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */,
|
84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */,
|
||||||
);
|
);
|
||||||
|
@ -524,9 +518,7 @@
|
||||||
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
|
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
|
||||||
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
|
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
|
||||||
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
|
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
|
||||||
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */,
|
|
||||||
84288A021F6A3D8000395871 /* RelatedObjectsMap+Database.swift in Sources */,
|
84288A021F6A3D8000395871 /* RelatedObjectsMap+Database.swift in Sources */,
|
||||||
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */,
|
|
||||||
84F20F8F1F180D8700D8E682 /* AuthorsTable.swift in Sources */,
|
84F20F8F1F180D8700D8E682 /* AuthorsTable.swift in Sources */,
|
||||||
84288A001F6A3C4400395871 /* DatabaseObject+Database.swift in Sources */,
|
84288A001F6A3C4400395871 /* DatabaseObject+Database.swift in Sources */,
|
||||||
8477ACBC2221E76F00DF7F37 /* SearchTable.swift in Sources */,
|
8477ACBC2221E76F00DF7F37 /* SearchTable.swift in Sources */,
|
||||||
|
|
|
@ -19,7 +19,6 @@ final class ArticlesTable: DatabaseTable {
|
||||||
private let queue: DatabaseQueue
|
private let queue: DatabaseQueue
|
||||||
private let statusesTable: StatusesTable
|
private let statusesTable: StatusesTable
|
||||||
private let authorsLookupTable: DatabaseLookupTable
|
private let authorsLookupTable: DatabaseLookupTable
|
||||||
private let attachmentsLookupTable: DatabaseLookupTable
|
|
||||||
private var databaseArticlesCache = [String: DatabaseArticle]()
|
private var databaseArticlesCache = [String: DatabaseArticle]()
|
||||||
|
|
||||||
private lazy var searchTable: SearchTable = {
|
private lazy var searchTable: SearchTable = {
|
||||||
|
@ -41,9 +40,6 @@ final class ArticlesTable: DatabaseTable {
|
||||||
|
|
||||||
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
||||||
self.authorsLookupTable = DatabaseLookupTable(name: DatabaseTableName.authorsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.authorID, relatedTable: authorsTable, relationshipName: RelationshipName.authors)
|
self.authorsLookupTable = DatabaseLookupTable(name: DatabaseTableName.authorsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.authorID, relatedTable: authorsTable, relationshipName: RelationshipName.authors)
|
||||||
|
|
||||||
let attachmentsTable = AttachmentsTable(name: DatabaseTableName.attachments)
|
|
||||||
self.attachmentsLookupTable = DatabaseLookupTable(name: DatabaseTableName.attachmentsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.attachmentID, relatedTable: attachmentsTable, relationshipName: RelationshipName.attachments)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Fetching Articles for Feed
|
// MARK: - Fetching Articles for Feed
|
||||||
|
@ -521,24 +517,22 @@ private extension ArticlesTable {
|
||||||
// 2. Fetch related objects.
|
// 2. Fetch related objects.
|
||||||
|
|
||||||
let authorsMap = authorsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
let authorsMap = authorsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
||||||
let attachmentsMap = attachmentsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
|
||||||
|
|
||||||
// 3. Create articles with related objects.
|
// 3. Create articles with related objects.
|
||||||
|
|
||||||
let articles = databaseArticles.map { (databaseArticle) -> Article in
|
let articles = databaseArticles.map { (databaseArticle) -> Article in
|
||||||
return articleWithDatabaseArticle(databaseArticle, authorsMap, attachmentsMap)
|
return articleWithDatabaseArticle(databaseArticle, authorsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Set(articles)
|
return Set(articles)
|
||||||
}
|
}
|
||||||
|
|
||||||
func articleWithDatabaseArticle(_ databaseArticle: DatabaseArticle, _ authorsMap: RelatedObjectsMap?, _ attachmentsMap: RelatedObjectsMap?) -> Article {
|
func articleWithDatabaseArticle(_ databaseArticle: DatabaseArticle, _ authorsMap: RelatedObjectsMap?) -> Article {
|
||||||
|
|
||||||
let articleID = databaseArticle.articleID
|
let articleID = databaseArticle.articleID
|
||||||
let authors = authorsMap?.authors(for: articleID)
|
let authors = authorsMap?.authors(for: articleID)
|
||||||
let attachments = attachmentsMap?.attachments(for: articleID)
|
|
||||||
|
|
||||||
return Article(databaseArticle: databaseArticle, accountID: accountID, authors: authors, attachments: attachments)
|
return Article(databaseArticle: databaseArticle, accountID: accountID, authors: authors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDatabaseArticles(with resultSet: FMResultSet) -> Set<DatabaseArticle> {
|
func makeDatabaseArticles(with resultSet: FMResultSet) -> Set<DatabaseArticle> {
|
||||||
|
@ -687,9 +681,7 @@ private extension ArticlesTable {
|
||||||
|
|
||||||
func saveRelatedObjectsForNewArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
func saveRelatedObjectsForNewArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||||
let databaseObjects = articles.databaseObjects()
|
let databaseObjects = articles.databaseObjects()
|
||||||
|
|
||||||
authorsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
authorsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
||||||
attachmentsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Updating Existing Articles
|
// MARK: - Updating Existing Articles
|
||||||
|
@ -713,7 +705,6 @@ private extension ArticlesTable {
|
||||||
|
|
||||||
func saveUpdatedRelatedObjects(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
|
func saveUpdatedRelatedObjects(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
|
||||||
updateRelatedObjects(\Article.authors, updatedArticles, fetchedArticles, authorsLookupTable, database)
|
updateRelatedObjects(\Article.authors, updatedArticles, fetchedArticles, authorsLookupTable, database)
|
||||||
updateRelatedObjects(\Article.attachments, updatedArticles, fetchedArticles, attachmentsLookupTable, database)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findUpdatedArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article]) -> Set<Article>? {
|
func findUpdatedArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article]) -> Set<Article>? {
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// AttachmentsTable.swift
|
|
||||||
// NetNewsWire
|
|
||||||
//
|
|
||||||
// Created by Brent Simmons on 7/15/17.
|
|
||||||
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import RSDatabase
|
|
||||||
import Articles
|
|
||||||
|
|
||||||
final class AttachmentsTable: DatabaseRelatedObjectsTable {
|
|
||||||
|
|
||||||
let name: String
|
|
||||||
let databaseIDKey = DatabaseKey.attachmentID
|
|
||||||
var cache = DatabaseObjectCache()
|
|
||||||
|
|
||||||
init(name: String) {
|
|
||||||
self.name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - DatabaseRelatedObjectsTable
|
|
||||||
|
|
||||||
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
|
||||||
if let attachment = Attachment(row: row) {
|
|
||||||
return attachment as DatabaseObject
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ struct DatabaseTableName {
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let authorsLookup = "authorsLookup"
|
static let authorsLookup = "authorsLookup"
|
||||||
static let statuses = "statuses"
|
static let statuses = "statuses"
|
||||||
static let attachments = "attachments"
|
|
||||||
static let attachmentsLookup = "attachmentsLookup"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DatabaseKey {
|
struct DatabaseKey {
|
||||||
|
@ -39,7 +37,6 @@ struct DatabaseKey {
|
||||||
static let datePublished = "datePublished"
|
static let datePublished = "datePublished"
|
||||||
static let dateModified = "dateModified"
|
static let dateModified = "dateModified"
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let attachments = "attachments"
|
|
||||||
static let searchRowID = "searchRowID"
|
static let searchRowID = "searchRowID"
|
||||||
|
|
||||||
// ArticleStatus
|
// ArticleStatus
|
||||||
|
@ -48,12 +45,6 @@ struct DatabaseKey {
|
||||||
static let userDeleted = "userDeleted"
|
static let userDeleted = "userDeleted"
|
||||||
static let dateArrived = "dateArrived"
|
static let dateArrived = "dateArrived"
|
||||||
|
|
||||||
// Attachment
|
|
||||||
static let attachmentID = "attachmentID"
|
|
||||||
static let mimeType = "mimeType"
|
|
||||||
static let sizeInBytes = "sizeInBytes"
|
|
||||||
static let durationInSeconds = "durationInSeconds"
|
|
||||||
|
|
||||||
// Tag
|
// Tag
|
||||||
static let tagName = "tagName"
|
static let tagName = "tagName"
|
||||||
|
|
||||||
|
@ -71,5 +62,4 @@ struct DatabaseKey {
|
||||||
struct RelationshipName {
|
struct RelationshipName {
|
||||||
|
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let attachments = "attachments"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,4 @@ extension Array where Element == DatabaseObject {
|
||||||
let authors = Set(self.map { $0 as! Author })
|
let authors = Set(self.map { $0 as! Author })
|
||||||
return authors.isEmpty ? nil : authors
|
return authors.isEmpty ? nil : authors
|
||||||
}
|
}
|
||||||
|
|
||||||
func asAttachments() -> Set<Attachment>? {
|
|
||||||
let attachments = Set(self.map { $0 as! Attachment })
|
|
||||||
return attachments.isEmpty ? nil : attachments
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,11 @@ import RSParser
|
||||||
extension Article {
|
extension Article {
|
||||||
|
|
||||||
init(databaseArticle: DatabaseArticle, accountID: String, authors: Set<Author>?, attachments: Set<Attachment>?) {
|
init(databaseArticle: DatabaseArticle, accountID: String, authors: Set<Author>?, attachments: Set<Attachment>?) {
|
||||||
self.init(accountID: accountID, articleID: databaseArticle.articleID, webFeedID: databaseArticle.webFeedID, uniqueID: databaseArticle.uniqueID, title: databaseArticle.title, contentHTML: databaseArticle.contentHTML, contentText: databaseArticle.contentText, url: databaseArticle.url, externalURL: databaseArticle.externalURL, summary: databaseArticle.summary, imageURL: databaseArticle.imageURL, bannerImageURL: databaseArticle.bannerImageURL, datePublished: databaseArticle.datePublished, dateModified: databaseArticle.dateModified, authors: authors, attachments: attachments, status: databaseArticle.status)
|
self.init(accountID: accountID, articleID: databaseArticle.articleID, webFeedID: databaseArticle.webFeedID, uniqueID: databaseArticle.uniqueID, title: databaseArticle.title, contentHTML: databaseArticle.contentHTML, contentText: databaseArticle.contentText, url: databaseArticle.url, externalURL: databaseArticle.externalURL, summary: databaseArticle.summary, imageURL: databaseArticle.imageURL, bannerImageURL: databaseArticle.bannerImageURL, datePublished: databaseArticle.datePublished, dateModified: databaseArticle.dateModified, authors: authors, status: databaseArticle.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(parsedItem: ParsedItem, maximumDateAllowed: Date, accountID: String, webFeedID: String, status: ArticleStatus) {
|
init(parsedItem: ParsedItem, maximumDateAllowed: Date, accountID: String, webFeedID: String, status: ArticleStatus) {
|
||||||
let authors = Author.authorsWithParsedAuthors(parsedItem.authors)
|
let authors = Author.authorsWithParsedAuthors(parsedItem.authors)
|
||||||
let attachments = Attachment.attachmentsWithParsedAttachments(parsedItem.attachments)
|
|
||||||
|
|
||||||
// Deal with future datePublished and dateModified dates.
|
// Deal with future datePublished and dateModified dates.
|
||||||
var datePublished = parsedItem.datePublished
|
var datePublished = parsedItem.datePublished
|
||||||
|
@ -35,7 +34,7 @@ extension Article {
|
||||||
dateModified = nil
|
dateModified = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.init(accountID: accountID, articleID: parsedItem.syncServiceID, webFeedID: webFeedID, uniqueID: parsedItem.uniqueID, title: parsedItem.title, contentHTML: parsedItem.contentHTML, contentText: parsedItem.contentText, url: parsedItem.url, externalURL: parsedItem.externalURL, summary: parsedItem.summary, imageURL: parsedItem.imageURL, bannerImageURL: parsedItem.bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, attachments: attachments, status: status)
|
self.init(accountID: accountID, articleID: parsedItem.syncServiceID, webFeedID: webFeedID, uniqueID: parsedItem.uniqueID, title: parsedItem.title, contentHTML: parsedItem.contentHTML, contentText: parsedItem.contentText, url: parsedItem.url, externalURL: parsedItem.externalURL, summary: parsedItem.summary, imageURL: parsedItem.imageURL, bannerImageURL: parsedItem.bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, status: status)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: inout DatabaseDictionary) {
|
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: inout DatabaseDictionary) {
|
||||||
|
@ -145,8 +144,6 @@ extension Article: DatabaseObject {
|
||||||
switch name {
|
switch name {
|
||||||
case RelationshipName.authors:
|
case RelationshipName.authors:
|
||||||
return databaseObjectArray(with: authors)
|
return databaseObjectArray(with: authors)
|
||||||
case RelationshipName.attachments:
|
|
||||||
return databaseObjectArray(with: attachments)
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
//
|
|
||||||
// Attachment+Database.swift
|
|
||||||
// NetNewsWire
|
|
||||||
//
|
|
||||||
// Created by Brent Simmons on 7/4/17.
|
|
||||||
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Articles
|
|
||||||
import RSDatabase
|
|
||||||
import RSParser
|
|
||||||
|
|
||||||
extension Attachment {
|
|
||||||
|
|
||||||
init?(row: FMResultSet) {
|
|
||||||
guard let url = row.string(forColumn: DatabaseKey.url) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let attachmentID = row.string(forColumn: DatabaseKey.attachmentID)
|
|
||||||
let mimeType = row.string(forColumn: DatabaseKey.mimeType)
|
|
||||||
let title = row.string(forColumn: DatabaseKey.title)
|
|
||||||
let sizeInBytes = row.optionalIntForColumn(DatabaseKey.sizeInBytes)
|
|
||||||
let durationInSeconds = row.optionalIntForColumn(DatabaseKey.durationInSeconds)
|
|
||||||
|
|
||||||
self.init(attachmentID: attachmentID, url: url, mimeType: mimeType, title: title, sizeInBytes: sizeInBytes, durationInSeconds: durationInSeconds)
|
|
||||||
}
|
|
||||||
|
|
||||||
init?(parsedAttachment: ParsedAttachment) {
|
|
||||||
self.init(attachmentID: nil, url: parsedAttachment.url, mimeType: parsedAttachment.mimeType, title: parsedAttachment.title, sizeInBytes: parsedAttachment.sizeInBytes, durationInSeconds: parsedAttachment.durationInSeconds)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func attachmentsWithParsedAttachments(_ parsedAttachments: Set<ParsedAttachment>?) -> Set<Attachment>? {
|
|
||||||
guard let parsedAttachments = parsedAttachments else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let attachments = parsedAttachments.compactMap{ Attachment(parsedAttachment: $0) }
|
|
||||||
return attachments.isEmpty ? nil : Set(attachments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extension Attachment: DatabaseObject {
|
|
||||||
|
|
||||||
public var databaseID: String {
|
|
||||||
return attachmentID
|
|
||||||
}
|
|
||||||
|
|
||||||
public func databaseDictionary() -> DatabaseDictionary? {
|
|
||||||
var d: DatabaseDictionary = [DatabaseKey.attachmentID: attachmentID, DatabaseKey.url: url]
|
|
||||||
if let mimeType = mimeType {
|
|
||||||
d[DatabaseKey.mimeType] = mimeType
|
|
||||||
}
|
|
||||||
if let title = title {
|
|
||||||
d[DatabaseKey.title] = title
|
|
||||||
}
|
|
||||||
if let sizeInBytes = sizeInBytes {
|
|
||||||
d[DatabaseKey.sizeInBytes] = NSNumber(value: sizeInBytes)
|
|
||||||
}
|
|
||||||
if let durationInSeconds = durationInSeconds {
|
|
||||||
d[DatabaseKey.durationInSeconds] = NSNumber(value: durationInSeconds)
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension FMResultSet {
|
|
||||||
|
|
||||||
func optionalIntForColumn(_ columnName: String) -> Int? {
|
|
||||||
let intValue = long(forColumn: columnName)
|
|
||||||
if intValue < 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return intValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Set where Element == Attachment {
|
|
||||||
|
|
||||||
func databaseDictionaries() -> [DatabaseDictionary] {
|
|
||||||
return self.compactMap { $0.databaseDictionary() }
|
|
||||||
}
|
|
||||||
|
|
||||||
func databaseObjects() -> [DatabaseObject] {
|
|
||||||
return self.compactMap { $0 as DatabaseObject }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,13 +12,6 @@ import Articles
|
||||||
|
|
||||||
extension RelatedObjectsMap {
|
extension RelatedObjectsMap {
|
||||||
|
|
||||||
func attachments(for articleID: String) -> Set<Attachment>? {
|
|
||||||
if let objects = self[articleID] {
|
|
||||||
return objects.asAttachments()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func authors(for articleID: String) -> Set<Author>? {
|
func authors(for articleID: String) -> Set<Author>? {
|
||||||
if let objects = self[articleID] {
|
if let objects = self[articleID] {
|
||||||
return objects.asAuthors()
|
return objects.asAuthors()
|
||||||
|
|
|
@ -122,7 +122,6 @@ private extension ArticlePasteboardWriter {
|
||||||
static let starred = "starred"
|
static let starred = "starred"
|
||||||
static let userDeleted = "userDeleted"
|
static let userDeleted = "userDeleted"
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let attachments = "attachments"
|
|
||||||
|
|
||||||
// Author
|
// Author
|
||||||
static let authorName = "name"
|
static let authorName = "name"
|
||||||
|
@ -130,13 +129,6 @@ private extension ArticlePasteboardWriter {
|
||||||
static let authorAvatarURL = "avatarURL"
|
static let authorAvatarURL = "avatarURL"
|
||||||
static let authorEmailAddress = "emailAddress"
|
static let authorEmailAddress = "emailAddress"
|
||||||
|
|
||||||
// Attachment
|
|
||||||
static let attachmentURL = "url"
|
|
||||||
static let attachmentMimeType = "mimeType"
|
|
||||||
static let attachmentTitle = "title"
|
|
||||||
static let attachmentSizeInBytes = "sizeInBytes"
|
|
||||||
static let attachmentDurationInSeconds = "durationInSeconds"
|
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
static let accountID = "accountID"
|
static let accountID = "accountID"
|
||||||
}
|
}
|
||||||
|
@ -164,7 +156,6 @@ private extension ArticlePasteboardWriter {
|
||||||
d[Key.dateModified] = article.dateModified ?? nil
|
d[Key.dateModified] = article.dateModified ?? nil
|
||||||
d[Key.dateArrived] = article.status.dateArrived
|
d[Key.dateArrived] = article.status.dateArrived
|
||||||
d[Key.authors] = authorDictionaries() ?? nil
|
d[Key.authors] = authorDictionaries() ?? nil
|
||||||
d[Key.attachments] = attachmentDictionaries() ?? nil
|
|
||||||
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -183,19 +174,6 @@ private extension ArticlePasteboardWriter {
|
||||||
d[Key.authorAvatarURL] = author.avatarURL ?? nil
|
d[Key.authorAvatarURL] = author.avatarURL ?? nil
|
||||||
d[Key.authorEmailAddress] = author.emailAddress ?? nil
|
d[Key.authorEmailAddress] = author.emailAddress ?? nil
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func attachmentDictionary(_ attachment: Attachment) -> [String: Any] {
|
|
||||||
var d = [String: Any]()
|
|
||||||
|
|
||||||
d[Key.attachmentURL] = attachment.url
|
|
||||||
d[Key.attachmentMimeType] = attachment.mimeType ?? nil
|
|
||||||
d[Key.attachmentTitle] = attachment.title ?? nil
|
|
||||||
d[Key.attachmentSizeInBytes] = attachment.sizeInBytes ?? nil
|
|
||||||
d[Key.attachmentDurationInSeconds] = attachment.durationInSeconds ?? nil
|
|
||||||
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,12 +183,5 @@ private extension ArticlePasteboardWriter {
|
||||||
}
|
}
|
||||||
return authors.map{ authorDictionary($0) }
|
return authors.map{ authorDictionary($0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachmentDictionaries() -> [[String: Any]]? {
|
|
||||||
guard let attachments = article.attachments, !attachments.isEmpty else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return attachments.map { attachmentDictionary($0) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -588,7 +588,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
||||||
let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
|
let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
|
||||||
let prototypeID = "prototype"
|
let prototypeID = "prototype"
|
||||||
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
|
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
|
||||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, attachments: nil, status: status)
|
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
|
||||||
|
|
||||||
let prototypeCellData = TimelineCellData(article: prototypeArticle, showFeedName: showingFeedNames, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil)
|
let prototypeCellData = TimelineCellData(article: prototypeArticle, showFeedName: showingFeedNames, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil)
|
||||||
let height = TimelineCellLayout.height(for: 100, cellData: prototypeCellData, appearance: cellAppearance)
|
let height = TimelineCellLayout.height(for: 100, cellData: prototypeCellData, appearance: cellAppearance)
|
||||||
|
|
|
@ -450,7 +450,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||||
|
|
||||||
let prototypeID = "prototype"
|
let prototypeID = "prototype"
|
||||||
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
|
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
|
||||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, attachments: nil, status: status)
|
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
|
||||||
|
|
||||||
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize)
|
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue